%!TEX root = std.tex
\rSec0[quantities]{Quantities and units library}

\rSec1[quantities.summary]{Summary}

\pnum
This Clause describes components for dealing with quantities and units,
as summarized in \tref{quantities.summary}.

\begin{modularlibsumtab}{Quantities and units library summary}{quantities.summary}
\ref{qty.utils}         & Utilities                              & \tcode{mp_units.core} \\
\ref{qty.ref}           & Reference                              & \\
\ref{qty.rep}           & Representation                         & \\
\ref{qty}               & Quantity                               & \\
\ref{qty.pt}            & Quantity point                         & \\ \rowsep
\ref{qty.systems}       & Systems                                & \tcode{mp_units.systems} \\
\ref{qty.chrono}        & \tcode{std::chrono} interoperability   & \\
\end{modularlibsumtab}

\ednote{
Following the SG16 recommendation at \url{https://lists.isocpp.org/sg16/2024/10/4490.php},
the \fakegrammarterm{universal-character-name}s should be replaced by their UTF-8 code points.
}

\rSec1[mp.units.syns]{mp-units module synopses}

\rSec2[mp.units.syn]{Module \tcode{mp_units} synopsis}

\indexmodule{mp_units}%
\begin{codeblock}
export module mp_units;

export import mp_units.core;
export import mp_units.systems;
\end{codeblock}

\rSec2[mp.units.core.syn]{Module \tcode{mp_units.core} synopsis}
\indexmodule{mp_units.core}%
\begin{codeblock}
// mostly freestanding
export module mp_units.core;

import std;

export namespace mp_units {

// \ref{qty.utils}, utilities

// \ref{qty.sym.txt}, symbol text

enum class @\libglobal{character_set}@ : std::int8_t { utf8, portable, default_character_set = utf8 };

template<std::size_t N, std::size_t M>
class symbol_text;

// \ref{qty.sym.expr}, symbolic expressions

// \ref{qty.sym.expr.types}, types

template<typename T, typename... Ts>
struct per;

template<typename F, int Num, int... Den>
  requires @\seebelownc@
struct power;

// \ref{qty.ref}, reference

// \ref{qty.dim}, dimension

// \ref{qty.dim.concepts}, concepts

template<typename T>
concept Dimension = @\seebelownc@;

template<typename T, auto D>
concept DimensionOf = @\seebelownc@;

// \ref{qty.dim.types}, types

template<symbol_text Symbol>
struct base_dimension;

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_dimension;

struct dimension_one;
inline constexpr dimension_one @\libglobal{dimension_one}@{};

// \ref{qty.dim.ops}, operations

consteval @\libconcept{Dimension}@ auto inverse(@\libconcept{Dimension}@ auto d);

template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Dimension}@ D>
  requires(Den != 0)
consteval @\libconcept{Dimension}@ auto pow(D d);
consteval @\libconcept{Dimension}@ auto sqrt(@\libconcept{Dimension}@ auto d);
consteval @\libconcept{Dimension}@ auto cbrt(@\libconcept{Dimension}@ auto d);

// \ref{qty.dim.sym.fmt}, symbol formatting

struct @\libglobal{dimension_symbol_formatting}@ {
  character_set char_set = character_set::default_character_set;
};

template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Dimension}@ D>
constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = {});

template<dimension_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Dimension}@ D>
consteval std::string_view dimension_symbol(D);

// \ref{qty.spec}, quantity specification

// \ref{qty.spec.concepts}, concepts

template<typename T>
concept QuantitySpec = @\seebelownc@;

template<typename T, auto QS>
concept QuantitySpecOf = @\seebelownc@;

// \ref{qty.spec.types}, types

// \ref{named.qty}, named

struct is_kind;
inline constexpr is_kind @\libglobal{is_kind}@{};

template<auto...>
struct quantity_spec;  // \notdef

template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Dim, Args...>;

template<@\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Eq, Args...>;

template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Args...>;

template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Eq, Args...>;

// \ref{derived.qty}, derived

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_quantity_spec;

// \ref{dimless.qty}, base quantity of dimension one

struct dimensionless;
inline constexpr dimensionless @\libglobal{dimensionless}@{};

// \ref{kind.of.qty}, kind of

template<@\libconcept{QuantitySpec}@ Q>
  requires @\seebelownc@
struct kind_of_;
template<@\libconcept{QuantitySpec}@ auto Q>
  requires requires { typename kind_of_<decltype(Q)>; }
inline constexpr kind_of_<decltype(Q)> @\libglobal{kind_of}@{};

// \ref{qty.spec.ops}, operations

consteval @\libconcept{QuantitySpec}@ auto inverse(@\libconcept{QuantitySpec}@ auto q);

template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{QuantitySpec}@ Q>
  requires(Den != 0)
consteval @\libconcept{QuantitySpec}@ auto pow(Q q);
consteval @\libconcept{QuantitySpec}@ auto sqrt(@\libconcept{QuantitySpec}@ auto q);
consteval @\libconcept{QuantitySpec}@ auto cbrt(@\libconcept{QuantitySpec}@ auto q);

// \ref{qty.spec.hier.algos}, hierarchy algorithms

// \ref{qty.spec.conv}, conversion

consteval bool implicitly_convertible(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool explicitly_convertible(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool castable(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool interconvertible(@\libconcept{QuantitySpec}@ auto qs1, @\libconcept{QuantitySpec}@ auto qs2);

// \ref{qty.get.kind}, \tcode{get_kind}

template<@\libconcept{QuantitySpec}@ Q>
consteval @\seebelownc@ get_kind(Q);

// \ref{get.common.qty.spec}, \tcode{get_common_quantity_spec}

consteval @\libconcept{QuantitySpec}@ auto get_common_quantity_spec(@\libconcept{QuantitySpec}@ auto... qs)
  requires @\seebelownc@;

// \ref{qty.unit}, unit

// \ref{qty.unit.mag}, magnitude

// \ref{qty.unit.mag.concepts}, concepts

template<typename T>
concept MagConstant = @\seebelownc@;

template<typename T>
concept UnitMagnitude = @\seebelownc@;

// \ref{qty.unit.mag.types}, types

template<symbol_text Symbol, long double Value>
  requires(Value > 0)
struct mag_constant;

// \ref{qty.unit.mag.ops}, operations

template<@\exposconceptnc{MagArg}@ auto V>
constexpr @\libconcept{UnitMagnitude}@ auto mag = @\seebelownc@;

template<std::intmax_t N, std::intmax_t D>
  requires(N > 0)
constexpr @\libconcept{UnitMagnitude}@ auto mag_ratio = @\seebelownc@;

template<@\exposconceptnc{MagArg}@ auto Base, int Num, int Den = 1>
constexpr @\libconcept{UnitMagnitude}@ auto mag_power = @\seebelownc@;

// constants

inline constexpr struct @\libglobal{pi}@ final :
    mag_constant<{u8"\u03C0" /* @\unicode{03c0}{GREEK SMALL LETTER PI}@ */, "pi"},
                 std::numbers::pi_v<long double>> {
} @\libglobal{pi}@;

inline constexpr auto \u03C0 /* @\unicode{03c0}{GREEK SMALL LETTER PI}@ */ = pi;

// \ref{qty.unit.traits}, traits

template<@\libconcept{Unit}@ auto U>
constexpr bool space_before_unit_symbol = true;

template<>
inline constexpr bool @\libspec{space_before_unit_symbol}{one}@<one> = false;

// \ref{qty.unit.concepts}, concepts

template<typename T>
concept Unit = @\seebelownc@;

template<typename T>
concept PrefixableUnit = @\seebelownc@;

template<typename T>
concept AssociatedUnit = @\seebelownc@;

template<typename U, auto QS>
concept UnitOf = @\seebelownc@;

// \ref{qty.unit.types}, types

// \ref{qty.scaled.unit}, scaled

template<@\libconcept{UnitMagnitude}@ auto M, @\libconcept{Unit}@ U>
  requires @\seebelownc@
struct scaled_unit;

// \ref{qty.named.unit}, named

template<symbol_text Symbol, auto...>
struct named_unit;  // \notdef

template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS>
  requires @\seebelownc@
struct named_unit<Symbol, QS>;

template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS, @\libconcept{PointOrigin}@ auto PO>
  requires @\seebelownc@
struct named_unit<Symbol, QS, PO>;

template<symbol_text Symbol>
  requires @\seebelownc@
struct named_unit<Symbol>;

template<symbol_text Symbol, @\libconcept{Unit}@ auto U>
  requires @\seebelownc@
struct named_unit<Symbol, U>;

template<symbol_text Symbol, @\libconcept{Unit}@ auto U, @\libconcept{PointOrigin}@ auto PO>
  requires @\seebelownc@
struct named_unit<Symbol, U, PO>;

template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS>
  requires @\seebelownc@
struct named_unit<Symbol, U, QS>;

template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS,
         @\libconcept{PointOrigin}@ auto PO>
  requires @\seebelownc@
struct named_unit<Symbol, U, QS, PO>;

// \ref{qty.prefixed.unit}, prefixed

template<symbol_text Symbol, @\libconcept{UnitMagnitude}@ auto M, @\libconcept{PrefixableUnit}@ auto U>
  requires @\seebelownc@
struct prefixed_unit;

// \ref{qty.common.unit}, common

template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
struct common_unit;

// \ref{qty.derived.unit}, derived

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_unit;

// \ref{qty.unit.one}, one

struct one;
inline constexpr one @\libglobal{one}@{};

// named derived units of a quantity of dimension one

inline constexpr struct @\libglobal{percent}@ final : named_unit<"%", mag_ratio<1, 100> * one> {
} @\libglobal{percent}@;

inline constexpr struct @\libglobal{per_mille}@ final :
    named_unit<symbol_text{u8"\u2030" /* @\unicode{2030}{PER MILLE SIGN}@ */, "%o"},
               mag_ratio<1, 1000> * one> {
} @\libglobal{per_mille}@;

inline constexpr struct @\libglobal{parts_per_million}@ final :
    named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {
} @\libglobal{parts_per_million}@;

inline constexpr auto @\libglobal{ppm}@ = parts_per_million;

// \ref{qty.unit.ops}, operations

consteval @\libconcept{Unit}@ auto inverse(@\libconcept{Unit}@ auto u);

template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Unit}@ U>
  requires @\seebelownc@
consteval @\libconcept{Unit}@ auto pow(U u);
consteval @\libconcept{Unit}@ auto sqrt(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto cbrt(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto square(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto cubic(@\libconcept{Unit}@ auto u);

// \ref{qty.unit.cmp}, comparison

template<@\libconcept{Unit}@ From, @\libconcept{Unit}@ To>
consteval bool convertible(From from, To to);

// \ref{qty.unit.obs}, observers

consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(@\libconcept{AssociatedUnit}@ auto u);
consteval @\libconcept{Unit}@ auto get_unit(@\libconcept{AssociatedUnit}@ auto u);

consteval @\libconcept{Unit}@ auto get_common_unit(@\libconcept{Unit}@ auto... us)
  requires @\seebelownc@;

// \ref{qty.unit.sym.fmt}, symbol formatting

enum class @\libglobal{unit_symbol_solidus}@ : std::int8_t {
  one_denominator,
  always,
  never,
  default_denominator = one_denominator
};

enum class @\libglobal{unit_symbol_separator}@ : std::int8_t {
  space,
  half_high_dot,
  default_separator = space
};

struct @\libglobal{unit_symbol_formatting}@ {
  character_set char_set = character_set::default_character_set;
  unit_symbol_solidus solidus = unit_symbol_solidus::default_denominator;
  unit_symbol_separator separator = unit_symbol_separator::default_separator;
};

template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Unit}@ U>
constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {});

template<unit_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Unit}@ U>
consteval std::string_view unit_symbol(U);

// \ref{qty.ref.concepts}, concepts

template<typename T>
concept @\deflibconcept{Reference}@ = @\seebelownc@;

template<typename T, auto QS>
concept @\deflibconcept{ReferenceOf}@ = @\seebelownc@;

// \ref{qty.ref.syn}, class template \tcode{reference}

template<@\libconcept{QuantitySpec}@ Q, @\libconcept{Unit}@ U>
struct reference;

// \ref{qty.ref.ops}, operations

template<typename FwdRep, @\libconcept{Reference}@ R,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R r);

template<typename FwdRep, @\libconcept{Reference}@ R,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr @\libconcept{Quantity}@ auto operator/(FwdRep&& lhs, R);

template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator*(FwdQ&& q, R);

template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator/(FwdQ&& q, R);

template<@\libconcept{Reference}@ R, typename Rep>
  requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator*(R, Rep&&) = delete;

template<@\libconcept{Reference}@ R, typename Rep>
  requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator/(R, Rep&&) = delete;

template<@\libconcept{Reference}@ R, typename Q>
  requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator*(R, Q&&) = delete;

template<@\libconcept{Reference}@ R, typename Q>
  requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator/(R, Q&&) = delete;

// \ref{qty.ref.obs}, observers

template<typename Q, typename U>
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(reference<Q, U>);

template<typename Q, typename U>
consteval @\libconcept{Unit}@ auto get_unit(reference<Q, U>);

consteval @\libconcept{AssociatedUnit}@ auto get_common_reference(@\libconcept{AssociatedUnit}@ auto u1,
                                                   @\libconcept{AssociatedUnit}@ auto u2,
                                                   @\libconcept{AssociatedUnit}@ auto... rest)
  requires @\seebelownc@;

template<@\libconcept{Reference}@ R1, @\libconcept{Reference}@ R2, @\libconcept{Reference}@... Rest>
consteval @\libconcept{Reference}@ auto get_common_reference(R1 r1, R2 r2, Rest... rest)
  requires @\seebelownc@;

// \ref{qty.rep}, representation

enum class @\libglobal{quantity_character}@ { scalar, complex, vector, tensor };

// \ref{qty.rep.traits}, traits

// \ref{qty.fp.traits}, floating-point

template<typename Rep>
constexpr bool treat_as_floating_point = @\seebelownc@;

// \ref{qty.char.traits}, quantity character

template<typename T>
constexpr bool disable_scalar = false;
template<>
inline constexpr bool @\libspec{disable_scalar}{bool}@<bool> = true;
template<typename T>
constexpr bool @\libspec{disable_scalar}{std::complex}@<std::complex<T>> = true;

template<typename T>
constexpr bool disable_complex = false;

template<typename T>
constexpr bool disable_vector = false;

// \ref{qty.val.traits}, values

template<typename Rep>
struct representation_values;

// \ref{qty.rep.cpos}, customization point objects

inline namespace @\unspec@ {

inline constexpr @\unspec@ real = @\unspec@;
inline constexpr @\unspec@ imag = @\unspec@;
inline constexpr @\unspec@ modulus = @\unspec@;

inline constexpr @\unspec@ magnitude = @\unspec@;

}

// \ref{qty.rep.concepts}, concepts

template<typename T>
concept Representation = @\seebelownc@;

template<typename T, quantity_character Ch>
concept RepresentationOf = @\seebelownc@;

// \ref{qty}, quantity

// \ref{qty.like}, interoperability

template<typename T>
struct quantity_like_traits;  // \notdef

template<typename T>
concept QuantityLike = @\seebelownc@;

// \ref{qty.syn}, class template \tcode{quantity}

template<typename T>
concept Quantity = @\seebelownc@;

template<typename Q, auto QS>
concept QuantityOf = @\seebelownc@;

template<@\libconcept{Reference}@ auto R, @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class quantity;

// \ref{qty.delta}, construction helper \tcode{delta}

template<@\libconcept{Reference}@ R>
struct delta_;

template<@\libconcept{Reference}@ auto R>
constexpr delta_<decltype(R)> @\libglobal{delta}@{};

// \ref{qty.non.mem.conv}, non-member conversions

template<@\libconcept{Unit}@ auto ToU, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);

template<@\libconcept{Representation}@ ToRep, @\seebelownc@>
  requires @\seebelownc@
constexpr quantity<@\seebelownc@, ToRep> value_cast(@\seebelownc@ q);

template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);

template<@\libconcept{Quantity}@ ToQ, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);

template<@\libconcept{QuantitySpec}@ auto ToQS, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto quantity_cast(@\seebelownc@ q);

}

// \ref{qty.common.type}, \tcode{std::common_type} specializations

template<mp_units::@\libconcept{Quantity}@ Q1, mp_units::@\libconcept{Quantity}@ Q2>
  requires @\seebelownc@
struct std::common_type<Q1, Q2>;

template<mp_units::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
  requires @\seebelownc@
struct std::common_type<Q, Value>;

template<mp_units::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
  requires requires { typename std::common_type<Q, Value>; }
struct @\libspec{std::common_type}{quantity}@<Value, Q> : std::common_type<Q, Value> {};

namespace mp_units {

// \ref{qty.pt}, quantity point

// \ref{qty.pt.orig}, point origin

// \ref{qty.pt.orig.concepts}, concepts

template<typename T>
concept PointOrigin = @\seebelownc@;

template<typename T, auto QS>
concept PointOriginFor = @\seebelownc@;

// \ref{qty.pt.orig.types}, types

// \ref{qty.abs.pt.orig}, absolute

template<@\libconcept{QuantitySpec}@ auto QS>
struct absolute_point_origin;

// \ref{qty.rel.pt.orig}, relative

template<@\libconcept{QuantityPoint}@ auto QP>
struct relative_point_origin;

// \ref{qty.zeroth.pt.orig}, zeroth

template<@\libconcept{QuantitySpec}@ auto QS>
struct zeroth_point_origin_;

template<@\libconcept{QuantitySpec}@ auto QS>
constexpr zeroth_point_origin_<QS> @\libglobal{zeroth_point_origin}@{};

// \ref{qty.def.pt.orig}, default

template<@\libconcept{Reference}@ R>
consteval @\libconcept{PointOriginFor}@<get_quantity_spec(R{})> auto default_point_origin(R);

// \ref{qty.pt.like}, interoperability

template<typename T>
struct quantity_point_like_traits;  // \notdef

template<typename T>
concept QuantityPointLike = @\seebelownc@;

// \ref{qty.pt.syn}, class template \tcode{quantity_point}

template<typename T>
concept QuantityPoint = @\seebelownc@;

template<typename QP, auto V>
concept QuantityPointOf = @\seebelownc@;

template<@\libconcept{Reference}@ auto R,
         @\libconcept{PointOriginFor}@<get_quantity_spec(R)> auto PO = default_point_origin(R),
         @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class quantity_point;

// \ref{qty.point}, construction helper \tcode{point}

template<@\libconcept{Reference}@ R>
struct point_;

template<@\libconcept{Reference}@ auto R>
constexpr point_<decltype(R)> @\libglobal{point}@{};

// \ref{qty.pt.non.mem.conv}, non-member conversions

template<@\libconcept{Unit}@ auto ToU, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);

template<@\libconcept{Representation}@ ToRep, @\seebelownc@>
  requires @\seebelownc@
constexpr quantity_point<@\seebelownc@, @\seebelownc@, ToRep> value_cast(@\seebelownc@ qp);

template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);

template<@\libconcept{Quantity}@ ToQ, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);

template<@\libconcept{QuantityPoint}@ ToQP, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);

template<@\libconcept{QuantitySpec}@ auto ToQS, @\seebelownc@>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto quantity_cast(@\seebelownc@ qp);

}
\end{codeblock}

\rSec2[mp.units.systems.syn]{Module \tcode{mp_units.systems} synopsis}
\indexmodule{mp_units.systems}%
\begin{codeblock}
export module mp_units.systems;

export import mp_units.core;
import std;

export namespace mp_units {

// \ref{qty.chrono}, \tcode{std::chrono} interoperability

template<typename Rep, typename Period>
struct quantity_like_traits<std::chrono::duration<Rep, Period>>;

template<typename Clock>
struct chrono_point_origin_;
template<typename Clock>
constexpr chrono_point_origin_<Clock> @\libglobal{chrono_point_origin}@{};

template<typename Clock, typename Rep, typename Period>
struct quantity_point_like_traits<
  std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>>;

}
\end{codeblock}

\rSec1[qty.utils]{Utilities}

\rSec2[qty.utils.non.types]{Non-types}

\indexlibraryglobalexpos{is-specialization-of}
\indexlibraryglobalexpos{is-derived-from-specialization-of}
\begin{itemdecl}
template<typename T, template<@\seebelow@> typename U>
consteval bool @\exposidnc{is-specialization-of}@();               // \expos
template<typename T, template<@\seebelow@> typename U>
consteval bool @\exposidnc{is-derived-from-specialization-of}@();  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
For the first signature,
\tcode{true} of \tcode{T} is a specialization of \tcode{U}, and
\tcode{false} otherwise.
\item
For the second signature,
\tcode{true} if \tcode{T} has exactly one public base class
that is a specialization of \tcode{U}
and has no other base class that is a specialization of \tcode{U}, and
\tcode{false} otherwise.
\end{itemize}

\pnum
\remarks
An implementation provides enough overloads for all arguments to \tcode{U}.
\end{itemdescr}

\rSec2[qty.ratio]{Ratio}

\indexlibraryglobalexpos{ratio}
\indexlibrarymemberexpos{operator==}{ratio}
\indexlibrarymemberexpos{operator<=>}{ratio}
\indexlibrarymemberexpos{operator-}{ratio}
\indexlibrarymemberexpos{operator+}{ratio}
\indexlibrarymemberexpos{operator/}{ratio}
\indexlibraryexposmemberexpos{is-integral}{ratio}
\begin{codeblock}
namespace mp_units {

struct @\exposidnc{ratio}@ {  // \expos
  std::intmax_t num;
  std::intmax_t den;

  consteval @\exposidnc{ratio}@(std::intmax_t n, std::intmax_t d = 1);

  friend consteval bool operator==(@\exposidnc{ratio}@, @\exposidnc{ratio}@) = default;
  friend consteval auto operator<=>(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs) { return (lhs - rhs).num <=> 0; }

  friend consteval @\exposidnc{ratio}@ operator-(@\exposidnc{ratio}@ r) { return {-r.num, r.den}; }

  friend consteval @\exposidnc{ratio}@ operator+(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs)
  {
    return {lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den};
  }

  friend consteval @\exposidnc{ratio}@ operator-(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs) { return lhs + (-rhs); }

  friend consteval @\exposidnc{ratio}@ operator*(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs);

  friend consteval @\exposidnc{ratio}@ operator/(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs)
  {
    return lhs * @\exposidnc{ratio}@{rhs.den, rhs.num};
  }
};

consteval bool @\exposidnc{is-integral}@(@\exposidnc{ratio}@ r) { return r.num % r.den == 0; }

consteval @\exposidnc{ratio}@ @\exposidnc{common-ratio}@(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);

}
\end{codeblock}

\pnum
\exposid{ratio} represents the rational number $\tcode{num}/\tcode{den}$.

\pnum
Unless otherwise specified,
in the following descriptions,
let \tcode{R(r)} be \tcode{std::ratio<N, D>},
where \tcode{N} and \tcode{D} are the values of \tcode{r.num} and \tcode{r.den}.

\indexlibraryctorexpos{ratio}
\begin{itemdecl}
consteval @\exposidnc{ratio}@(std::intmax_t n, std::intmax_t d = 1);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{N} and \tcode{D} be the values of \tcode{n} and \tcode{d}.
Let \tcode{R} be \tcode{std::ratio<N, D>}.

\pnum
\effects
Equivalent to
\tcode{R}.

\pnum
\ensures
\tcode{num == R::num \&\& den == R::den} is \tcode{true}.
\end{itemdescr}

\indexlibrarymemberexpos{operator*}{ratio}
\begin{itemdecl}
friend consteval @\exposidnc{ratio}@ operator*(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Res} be \tcode{std::ratio_multiply<R(lhs), R(rhs)>}.

\pnum
\effects
Equivalent to:
\tcode{return \{Res::num, Res::den\};}
\end{itemdescr}

\indexlibraryexposmemberexpos{common-ratio}{ratio}
\begin{itemdecl}
consteval @\exposidnc{ratio}@ @\exposidnc{common-ratio}@(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Res} be equal to
\begin{codeblock}
std::common_type<std::chrono::duration<int, R(r1)>,
                 std::chrono::duration<int, R(r2)>>::type::period
\end{codeblock}

\pnum
\effects
Equivalent to:
\tcode{return \{Res::num, Res::den\};}
\end{itemdescr}

\rSec2[qty.sym.txt]{Symbol text}

\indexlibraryglobal{symbol_text}
\begin{codeblock}
namespace mp_units {

template<std::size_t N, std::size_t M>
class symbol_text {
public:
  std::fixed_u8string<N> @\exposidnc{utf8}@;    // \expos
  std::fixed_string<M> @\exposidnc{portable}@;  // \expos

  // constructors
  constexpr symbol_text(char portable);
  consteval symbol_text(const char (&portable)[N + 1]);
  constexpr symbol_text(const std::fixed_string<N>& portable);
  consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]);
  constexpr symbol_text(const std::fixed_u8string<N>& utf8,
                        const std::fixed_string<M>& portable);

  // observers
  constexpr const auto& @\libmember{utf8}{symbol_text}@() const { return @\exposidnc{utf8}@; }
  constexpr const auto& @\libmember{portable}{symbol_text}@() const { return @\exposidnc{portable}@; }
  constexpr bool @\libmember{empty}{symbol_text}@() const { return utf8().empty(); }

  // string operations
  template<std::size_t N2, std::size_t M2>
  friend constexpr symbol_text<N + N2, M + M2> operator+(const symbol_text& lhs,
                                                         const symbol_text<N2, M2>& rhs);

  // comparison
  template<std::size_t N2, std::size_t M2>
  friend constexpr bool operator==(const symbol_text& lhs,
                                   const symbol_text<N2, M2>& rhs) noexcept;
  template<std::size_t N2, std::size_t M2>
  friend constexpr auto operator<=>(const symbol_text& lhs,
                                    const symbol_text<N2, M2>& rhs) noexcept;
};

symbol_text(char) -> symbol_text<1, 1>;

template<std::size_t N>
symbol_text(const char (&)[N]) -> symbol_text<N - 1, N - 1>;

template<std::size_t N>
symbol_text(const std::fixed_string<N>&) -> symbol_text<N, N>;

template<std::size_t N, std::size_t M>
symbol_text(const char8_t (&)[N], const char (&)[M]) -> symbol_text<N - 1, M - 1>;

template<std::size_t N, std::size_t M>
symbol_text(const std::fixed_u8string<N>&, const std::fixed_string<M>&) -> symbol_text<N, M>;

}
\end{codeblock}

\pnum
\tcode{symbol_text} represents a symbol text.
\exposid{utf8} stores its UTF-8 representation, and
\exposid{portable} stores its portable representation.
\tcode{symbol_text<N, M>} is a structural type\irefcppx{temp.param}{term.structural.type}.

\pnum
In the descriptions that follow,
it is a \Fundescx{Precondition} that
\begin{itemize}
\item
values of \tcode{char} are in the basic literal character set\irefcpp{lex.charset}, and
\item
for a parameter of the form \tcode{const \placeholdernc{CharT} (\&\placeholdernc{txt})[\placeholder{M}]},
\tcode{(\placeholdernc{txt}[\placeholdernc{M} - 1] == \placeholdernc{CharT}())} is \tcode{true}.
\end{itemize}

\indexlibraryctor{symbol_text}
\begin{itemdecl}
constexpr symbol_text(char portable);
consteval symbol_text(const char (&portable)[N + 1]);
constexpr symbol_text(const std::fixed_string<N>& portable);
consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]);
constexpr symbol_text(const std::fixed_u8string<N>& utf8, const std::fixed_string<M>& portable);
\end{itemdecl}

\begin{itemdescr}
\pnum
For the constructors without a parameter named \tcode{utf8},
let \tcode{utf8} be:
\begin{codeblock}
std::bit_cast<std::fixed_u8string<N>>(std::basic_fixed_string(portable))
\end{codeblock}

\pnum
\effects
Equivalent to the \fakegrammarterm{mem-initializer-list}:
\begin{codeblock}
@\exposid{utf8}@{utf8}, @\exposidnc{portable}@{portable}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator+}{symbol_text}
\begin{itemdecl}
template<std::size_t N2, std::size_t M2>
friend constexpr symbol_text<N + N2, M + M2> operator+(const symbol_text& lhs,
                                                       const symbol_text<N2, M2>& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return symbol_text<N + N2, M + M2>(lhs.utf8() + rhs.utf8(),
                                   lhs.portable() + rhs.portable());
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator==}{symbol_text}
\indexlibrarymember{operator<=>}{symbol_text}
\begin{itemdecl}
template<std::size_t N2, std::size_t M2>
friend constexpr bool operator==(const symbol_text& lhs,
                                 const symbol_text<N2, M2>& rhs) noexcept;
template<std::size_t N2, std::size_t M2>
friend constexpr auto operator<=>(const symbol_text& lhs,
                                  const symbol_text<N2, M2>& rhs) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return std::make_tuple(std::cref(lhs.utf8()), std::cref(lhs.portable())) @\atsign@
       std::make_tuple(std::cref(rhs.utf8()), std::cref(rhs.portable()));
\end{codeblock}
\end{itemdescr}

\rSec2[qty.sym.expr]{Symbolic expressions}

\rSec3[qty.sym.expr.general]{General}

\pnum
Subclause \ref{qty.sym.expr} specifies the components
used to maintain ordered, simplified, and readable
argument lists in the names of specializations.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
int x = kg * km / square(h);  // error: cannot construct from
  // \tcode{derived_unit<si::kilo_<si::gram>, si::kilo_<si::metre>, per<power<non_si::hour, 2>>>}
\end{codeblock}
The library ensures \tcode{decltype(kg * km / square(h))} is styled-like as commented in diagnostics,
provided that, in the implementation-defined total order of types,
\tcode{decltype(kg)} is less than \tcode{decltype(km)}.
\end{example}

\rSec3[qty.sym.expr.concepts]{Concept \ecname{SymbolicConstant}}

\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{SymbolicConstant}@ =  // \expos
  std::is_empty_v<T> && std::is_final_v<T> && std::is_trivially_default_constructible_v<T> &&
  std::is_trivially_copy_constructible_v<T> && std::is_trivially_move_constructible_v<T> &&
  std::is_trivially_destructible_v<T>;
\end{itemdecl}

\pnum
The concept \exposconcept{SymbolicConstant}
is used to constrain the types
that are used in symbolic expressions.

\rSec3[qty.sym.expr.types]{Types}

\indexlibraryglobal{per}
\begin{codeblock}
namespace mp_units {

template<typename T, typename... Ts>
struct per final {};

}
\end{codeblock}

\pnum
\tcode{per} is used to store arguments with negative exponents.
A specialization of \tcode{per}
represents the product of the inverse of its template arguments.
A program that instantiates a specialization of \tcode{per}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\indexlibraryglobal{power}
\begin{codeblock}
namespace mp_units {

template<typename F, int Num, int... Den>
  requires @\seebelownc@
struct power final {
  using @\exposidnc{factor}@ = F;                              // \expos
  static constexpr @\exposidnc{ratio}@ @\exposidnc{exponent}@{Num, Den...};  // \expos
};

}
\end{codeblock}

\pnum
\tcode{power} represents a power\irefiev{102-02-08}
of the form $\tcode{F}^{\tcode{Num}/\tcode{Den}}$.
\begin{note}
\tcode{Den} is optional to shorten the type name when \tcode{Den} is \tcode{1}.
\end{note}
A program that instantiates a specialization of \tcode{power}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\pnum
Let \tcode{r} be \tcode{\exposidnc{ratio}\{Num, Den...\}}.
Let \tcode{\placeholder{is-valid-ratio}} be
\tcode{true} if \tcode{r} is a valid constant expression, and
\tcode{false} otherwise.
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\placeholdernc{is-valid-ratio}@ && (r > @\exposidnc{ratio}@{0}) && (r != @\exposidnc{ratio}@{1})
\end{codeblock}

\rSec3[qty.sym.expr.algos]{Algorithms}

\indexlibraryglobalexpos{expr-type}
\begin{codeblock}
template<typename T>
using @\exposidnc{expr-type}@ = @\seebelownc@;  // \expos
\end{codeblock}

\pnum
\tcode{\exposidnc{expr-type}<T>} denotes
\tcode{U} if \tcode{T} is of the form \tcode{power<U, Ints...>}, and
\tcode{T} otherwise.

\indexlibraryglobalexpos{type-less-impl}
\begin{itemdecl}
template<typename T, typename U>
consteval bool @\exposidnc{type-less-impl}@();  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{T} is less than \tcode{U}
in an implementation-defined total order for types, and
\tcode{false} otherwise.
\end{itemdescr}

\indexlibraryglobalexpos{type-less}
\begin{codeblock}
template<typename Lhs, typename Rhs>
struct @\exposidnc{type-less}@ :  // \expos
    std::bool_constant<@\exposidnc{is-specialization-of}@<Rhs, power>() ||
                       @\exposidnc{type-less-impl}@<@\exposidnc{expr-type}@<Lhs>, @\exposidnc{expr-type}@<Rhs>>()> {};
\end{codeblock}

\pnum
\exposid{type-less} meets the requirements of
the \tcode{Pred} parameter of the symbolic expression algorithms below.

\indexlibraryglobalexpos{type-list}
\indexlibraryglobalexpos{expr-fractions}
\begin{codeblock}
template<typename... Ts>
struct @\exposidnc{type-list}@ {};      // \expos

template<typename OneType, typename... Ts>
struct @\exposidnc{expr-fractions}@ {   // \expos
  using @\exposidnc{num}@ = @\seebelownc@;  // \expos
  using @\exposidnc{den}@ = @\seebelownc@;  // \expos
}
\end{codeblock}

\pnum
\exposid{expr-fractions} divides a symbolic expression to numerator and denominator parts.
Let \tcode{EF} be a specialization of \exposid{expr-fractions}.
\begin{itemize}
\item
If \tcode{EF} is of the form \tcode{\exposidnc{expr-fractions}<OneType, Ts..., per<Us...>>},
then
\begin{itemize}
\item
\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}<Ts...>}, and
\item
\tcode{EF::\exposidnc{den}} denotes \tcode{\exposidnc{type-list}<Us...>}.
\end{itemize}
\item
Otherwise, \tcode{EF} is of the form \tcode{\exposidnc{expr-fractions}<OneType, Ts...>}, and
\begin{itemize}
\item
\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}<Ts...>}, and
\item
\tcode{EF::\exposidnc{den}} denotes \tcode{\exposidnc{type-list}<>}.
\end{itemize}
\end{itemize}

\pnum
The symbolic expression algorithms perform operations on symbolic constants.
A symbolic constant is a type that is a model of \exposconcept{SymbolicConstant}.
\begin{example}
The dimension \tcode{dim_length}, the quantity \tcode{time}, and the unit \tcode{one} are symbolic constants.
\end{example}
The algorithms also support
powers with a symbolic constant base and a rational exponent,
products thereof, and
fractions thereof.

\indexlibraryglobalexpos{expr-multiply}
\indexlibraryglobalexpos{expr-divide}
\indexlibraryglobalexpos{expr-invert}
\indexlibraryglobalexpos{expr-pow}
\begin{itemdecl}
template<template<typename...> typename To, typename OneType,
         template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs>
consteval auto @\exposidnc{expr-multiply}@(Lhs, Rhs);        // \expos

template<template<typename...> typename To, typename OneType,
         template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs>
consteval auto @\exposidnc{expr-divide}@(Lhs lhs, Rhs rhs);  // \expos

template<template<typename...> typename To, typename OneType, typename T>
consteval auto @\exposidnc{expr-invert}@(T);                 // \expos

template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To,
         typename OneType, template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename T>
  requires(Den != 0)
consteval auto @\exposidnc{expr-pow}@(T);                    // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\begin{itemize}
\item
\tcode{OneType} is the neutral element\irefiev{102-01-19} of the operation, and
\item
\tcode{Pred} is a \oldconcept{BinaryTypeTrait}\irefcpp{meta.rqmts}
with a base characteristic of \tcode{std::bool_constant<B>}.
\tcode{Pred<T, U>} implements a total order for types;
\tcode{B} is \tcode{true} if \tcode{T} is ordered before \tcode{U}, and \tcode{false} otherwise.
\end{itemize}

\pnum
\effects
\pnum
First, inputs to the operations are obtained from the types of the function parameters.
If the type of a function parameter is:
\begin{itemize}
\item
A specialization of \tcode{To},
then its input is the product of its template arguments, and
the following also apply.
\item
A specialization of \tcode{per},
then its input is the product of the inverse of its template arguments, and
the following also apply.
\item
A specialization of the form \tcode{power<F, Num>},
then its input is $\tcode{F}^\tcode{Num}$, or
a specialization of the form \tcode{power<F, Num, Den>},
then its input is $\tcode{F}^{\tcode{Num}/\tcode{Den}}$, and
the following also applies.
\item
Otherwise, the input is the symbolic constant itself.
\end{itemize}
\begin{example}
Item by item, this algorithm step goes from the \Cpp{} parameter type
\tcode{decltype(km / square(h))},
styled in diagnostics like
\tcode{derived_unit<si::kilo_<si::metre>, per<power<non_si::hour, 2>>},
\begin{itemize}
\item
to $\tcode{decltype(km)} \times \tcode{per<power<decltype(h), 2>}$ (product of \tcode{To}'s arguments),
\item
to $\tcode{decltype(km)} \times 1/\tcode{power<decltype(h), 2>}$ (product of inverse of \tcode{per}'s arguments),
\item
to $\tcode{decltype(km)} \times 1/\tcode{decltype(h)}^2$ (\tcode{power}s as powers),
\item
to $\txtrm{a} \times 1/\txtrm{b}^2$ where $\txtrm{a} = \tcode{decltype(km)}$ and $\txtrm{b} = \tcode{decltype(h)}$ (symbolic substitution)
in the mathematical domain.
\end{itemize}
\end{example}

\pnum
Then, the operation takes place:
\begin{itemize}
\item
\exposid{expr-multiply} multiplies its inputs,
\item
\exposid{expr-divide} divides the input of its first parameter by the input of its second parameter,
\item
\exposid{expr-invert} divides $1$ by its input, and
\item
\exposid{expr-pow} raises its input to the $\tcode{Num}/\tcode{Den}$.
\end{itemize}

\pnum
Finally, let $r$ be the result of the operation simplified as follows:
\begin{itemize}
\item
All terms are part of the same fraction (if any).
\item
There is at most a single term with a given symbolic constant.
\item
There are no negative exponents.
\item
$1$ is only present as $r$ and as a numerator with a denominator not equal to $1$.
\end{itemize}
\begin{example}
Item by item: \\
$x \times 1/y \times 1/x^2$ \\
$= x/(y x^2)$ (single fraction) \\
$= x^{-1}/y$ (unique symbolic constants) \\
$= 1/(x^1 y)$ (positive exponents) \\
$= 1/(xy)$ (non-redundant $1$s) \\
\end{example}

\pnum
\returns
$r$ is mapped to the return type:
\begin{itemize}
\item
If $r = 1$, returns \tcode{OneType\{\}}.
\item
Otherwise, if $r$ is a symbolic constant, returns $r$.
\item
Otherwise, first applies the following mappings to the terms of $r$:
\begin{itemize}
\item
$x^{n/d}$ is mapped to \tcode{power<$x$, $n$, $d$>}, and
$x^{n}$ is mapped to \tcode{power<$x$, $n$>}, and
\item
$1$ is mapped to \tcode{OneType\{\}}.
\end{itemize}
\item
Then, a denominator $x$ of $r$ (if any) is mapped to \tcode{per<$x$>}.
\item
Then, sorts $r$ without \tcode{per} (if any) and
the template arguments of \tcode{per} (if any)
according to \tcode{Pred}.
\item
Finally, returns \tcode{To<$r$>\{\}}, where \tcode{per} (if any) is the last argument.
\end{itemize}

\pnum
\remarks
A valid template argument list for \tcode{To} and \tcode{per}
is formed by interspersing commas between each mapped term.
If a mapping to \tcode{std::intmax_t} is not representable,
the program is ill-formed.
\end{itemdescr}

\pnum
\exposid{expr-map} maps the contents of one symbolic expression to another resulting in a different type list.

\indexlibraryglobalexpos{expr-map}
\begin{itemdecl}
template<template<typename> typename Proj, template<typename...> typename To, typename OneType,
         template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename T>
consteval auto @\exposidnc{expr-map}@(T);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{\exposidnc{expr-type-map}<U>} be
\tcode{power<Proj<F>, Ints...>} if \tcode{U} is of the form \tcode{power<F, Ints...>}, and
\tcode{Proj<U>} otherwise,
\item
\tcode{\exposidnc{map-power}(u)} be
\tcode{pow<Ints...>(F\{\})} if \tcode{decltype(u)} is of the form \tcode{power<F, Ints...>}, and
\tcode{u} otherwise, and
\item
\tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{T::\exposidnc{nums}} and \tcode{T::\exposidnc{dens}}, respectively.
\end{itemize}

\pnum
\returns
\begin{codeblock}
(OneType{} * ... * @\exposidnc{map-power}@(@\exposidnc{expr-type-map}@<Nums>{})) /
(OneType{} * ... * @\exposidnc{map-power}@(@\exposidnc{expr-type-map}@<Dens>{}))
\end{codeblock}
\end{itemdescr}

\rSec1[qty.ref]{Reference}

\rSec2[qty.ref.general]{General}

\pnum
Subclause \ref{qty.ref} specifies the components
for describing the reference of a quantity\irefiev{112-01-01}.

\rSec2[qty.dim]{Dimension}

\rSec3[qty.dim.general]{General}

\pnum
Subclause \ref{qty.dim} specifies the components
for defining the dimension of a quantity\irefiev{112-01-11}.

\rSec3[qty.dim.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Dimension}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{dimension-interface}@>;

template<typename T>
concept @\defexposconceptnc{BaseDimension}@ =  // \expos
  @\libconcept{Dimension}@<T> && (@\exposidnc{is-derived-from-specialization-of}@<T, base_dimension>());

template<typename T, auto D>
concept @\deflibconcept{DimensionOf}@ = @\libconcept{Dimension}@<T> && @\libconcept{Dimension}@<decltype(D)> && (T{} == D);
\end{itemdecl}

\rSec3[qty.dim.types]{Types}

\begin{codeblock}
namespace mp_units {

template<symbol_text Symbol>
struct @\libglobal{base_dimension}@ : @\exposidnc{dimension-interface}@ {
  static constexpr auto @\exposidnc{symbol}@ = Symbol;  // \expos
};

}
\end{codeblock}

\pnum
\tcode{base_dimension} is used
to define the dimension of a base quantity\irefiev{112-01-08}.
\tcode{Symbol} is its symbolic representation.
\begin{example}
\begin{codeblock}
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
\end{codeblock}
\end{example}

\indexlibraryglobal{derived_dimension}
\begin{codeblock}
namespace mp_units {

template<typename... Expr>
struct @\exposidnc{derived-dimension-impl}@  // \expos
    : @\exposidnc{expr-fractions}@<struct dimension_one, Expr...> {};

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_dimension final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<Expr...> {};

}
\end{codeblock}

\pnum
\tcode{derived_dimension} is used by the library
to represent the dimension of a derived quantity\irefiev{112-01-10}.
\begin{example}
\begin{codeblock}
constexpr auto dim_acceleration = isq::speed.dimension / isq::dim_time;
int x = dim_acceleration;  // error: cannot construct from
  // \tcode{derived_dimension<isq::dim_length, per<power<isq::dim_time, 2>>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_dimension}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\indexlibraryglobal{dimension_one}
\begin{codeblock}
namespace mp_units {

struct dimension_one final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<> {};

}
\end{codeblock}

\pnum
\tcode{dimension_one} represents the dimension of a quantity of dimension one\irefiev{112-01-13}.

\rSec3[qty.dim.ops]{Operations}

\indexlibraryglobalexpos{dimension-interface}
\begin{codeblock}
namespace mp_units {

struct @\exposidnc{dimension-interface}@ {  // \expos
  template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
  friend consteval @\libconcept{Dimension}@ auto operator*(Lhs, Rhs);

  template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
  friend consteval @\libconcept{Dimension}@ auto operator/(Lhs, Rhs);

  template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
  friend consteval bool operator==(Lhs, Rhs);
};

}
\end{codeblock}

\indexlibrarymember{operator*}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator*(Lhs, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-multiply}<derived_dimension, struct dimension_one>(Lhs\{\}, Rhs\{\})}.
\end{itemdescr}

\indexlibrarymember{operator/}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator/(Lhs, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-divide}<derived_dimension, struct dimension_one>(Lhs\{\}, Rhs\{\})}.
\end{itemdescr}

\indexlibrarymember{operator==}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}

\indexlibrarymember{inverse}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto inverse(@\libconcept{Dimension}@ auto d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{dimension_one / d}.
\end{itemdescr}

\indexlibrarymember{pow}{Dimension}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Dimension}@ D>
  requires(Den != 0)
consteval @\libconcept{Dimension}@ auto pow(D d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-pow}<Num, Den, derived_dimension, struct dimension_one>(d)}.
\end{itemdescr}

\indexlibrarymember{sqrt}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto sqrt(@\libconcept{Dimension}@ auto d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(d)}.
\end{itemdescr}

\indexlibrarymember{cbrt}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto cbrt(@\libconcept{Dimension}@ auto d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(d)}.
\end{itemdescr}

\rSec3[qty.dim.sym.fmt]{Symbol formatting}

\indexlibrarymember{dimension_symbol_to}{Dimension}
\begin{itemdecl}
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Dimension}@ D>
constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = {});
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
TBD.

\pnum
\returns
TBD.
\end{itemdescr}

\indexlibrarymember{dimension_symbol}{Dimension}
\begin{itemdecl}
template<dimension_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Dimension}@ D>
consteval std::string_view dimension_symbol(D);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
TBD.
\end{codeblock}
\end{itemdescr}

\rSec2[qty.spec]{Quantity specification}

\rSec3[qty.spec.general]{General}

\pnum
Subclause \ref{qty.spec} specifies the components
for defining a quantity\irefiev{112-01-01}.

\rSec3[qty.spec.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{QuantitySpec}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{quantity-spec-interface}@>;

template<typename T>
concept @\defexposconceptnc{QuantityKindSpec}@ =                                   // \expos
  @\libconcept{QuantitySpec}@<T> && @\exposidnc{is-specialization-of}@<T, kind_of_>();

template<typename T>
concept @\defexposconceptnc{NamedQuantitySpec}@ =                                  // \expos
  @\libconcept{QuantitySpec}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, quantity_spec>() &&
  (!@\exposconceptnc{QuantityKindSpec}@<T>);

template<typename T>
concept @\defexposconceptnc{DerivedQuantitySpec}@ =                                // \expos
  @\libconcept{QuantitySpec}@<T> &&
  (@\exposidnc{is-specialization-of}@<T, derived_quantity_spec>() ||
   (@\exposconceptnc{QuantityKindSpec}@<T> &&
    @\exposidnc{is-specialization-of}@<decltype(auto(T::@\exposidnc{quantity-spec}@)), derived_quantity_spec>()));

template<auto Child, auto Parent>
concept @\defexposconceptnc{ChildQuantitySpecOf}@ = (@\exposidnc{is-child-of}@(Child, Parent));  // \expos

template<auto To, auto From>
concept @\defexposconceptnc{NestedQuantityKindSpecOf}@ =                           // \expos
  @\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> &&
  (get_kind(From) != get_kind(To)) && @\exposconceptnc{ChildQuantitySpecOf}@<To, get_kind(From).@\exposidnc{quantity-spec}@>;

template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecConvertibleTo}@ =                          // \expos
  @\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && implicitly_convertible(From, To);

template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecExplicitlyConvertibleTo}@ =                // \expos
  @\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && explicitly_convertible(From, To);

template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecCastableTo}@ =                             // \expos
  @\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && castable(From, To);

template<typename T, auto QS>
concept @\deflibconcept{QuantitySpecOf}@ =
  @\libconcept{QuantitySpec}@<T> && @\libconcept{QuantitySpec}@<decltype(QS)> && @\exposconceptnc{QuantitySpecConvertibleTo}@<T{}, QS> &&
  !@\exposconceptnc{NestedQuantityKindSpecOf}@<T{}, QS> &&
  (@\exposconceptnc{QuantityKindSpec}@<T> || !@\exposconceptnc{NestedQuantityKindSpecOf}@<QS, T{}>);

template<typename T>
concept @\defexposconceptnc{QSProperty}@ = (!@\libconcept{QuantitySpec}@<T>);                     // \expos
\end{itemdecl}

\rSec3[qty.spec.types]{Types}

\rSec4[named.qty]{Named}

\indexlibraryglobal{is_kind}
\indexlibraryglobal{quantity_spec}
\begin{codeblock}
namespace mp_units {

struct is_kind {};

template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Dim, Args...> : @\exposidnc{quantity-spec-interface}@ {
  using @\exposidnc{base-type}@ = quantity_spec;
  static constexpr @\exposconceptnc{BaseDimension}@ auto dimension = Dim;
  static constexpr quantity_character character = @\seebelownc@;
};

template<@\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Eq, Args...> : @\exposidnc{quantity-spec-interface}@ {
  using @\exposidnc{base-type}@ = quantity_spec;
  static constexpr auto @\exposidnc{equation}@ = Eq;
  static constexpr @\libconcept{Dimension}@ auto dimension = Eq.dimension;
  static constexpr quantity_character character = @\seebelownc@;
};

template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Args...> : @\exposidnc{quantity-spec-interface}@ {
  using @\exposidnc{base-type}@ = quantity_spec;
  static constexpr auto @\exposidnc{parent}@ = QS;
  static constexpr auto @\exposidnc{equation}@ = @\exposidnc{parent}@.@\exposidnc{equation}@;  // \expos, present only
    // if the \fakegrammarterm{qualified-id} \tcode{\exposidnc{parent}.\exposidnc{equation}} is valid and denotes an object
  static constexpr @\libconcept{Dimension}@ auto dimension = @\exposidnc{parent}@.dimension;
  static constexpr quantity_character character = @\seebelownc@;
};

template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
  requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Eq, QS>
struct quantity_spec<QS, Eq, Args...> : @\exposidnc{quantity-spec-interface}@ {
  using @\exposidnc{base-type}@ = quantity_spec;
  static constexpr auto @\exposidnc{parent}@ = QS;
  static constexpr auto @\exposidnc{equation}@ = Eq;
  static constexpr @\libconcept{Dimension}@ auto dimension = @\exposidnc{parent}@.dimension;
  static constexpr quantity_character character = @\seebelownc@;
};

}
\end{codeblock}

\pnum
A \defnadj{named}{quantity} is a type that models \exposconceptnc{NamedQuantitySpec}.
A specialization of \tcode{quantity_spec} is used as a base type when defining a named quantity.

\pnum
In the following descriptions, let \tcode{Q} be a named quantity defined with an alluded signature.
The identifier of \tcode{Q} represents its quantity name\irefiev{112-01-02}.

\pnum
Let \tcode{Ch} be an enumerator value of \tcode{quantity_character}.
The possible arguments to \tcode{quantity_spec} are
\begin{itemize}
\item
$(\text{a base quantity dimension}, \opt{\tcode{Ch}})$,
\item
$(\text{a quantity calculus}, \opt{\tcode{Ch}})$,
\item
$(\text{a named quantity}, \opt{\tcode{Ch}}, \opt{\tcode{is_kind}})$, and
\item
$(\text{a named quantity}, \text{a quantity calculus}, \opt{\tcode{Ch}}, \opt{\tcode{is_kind}})$.
\end{itemize}

\pnum
If the first argument is a base quantity dimension,
then \tcode{Q} is that base quantity\irefiev{112-01-08}.
If an argument is a quantity calculus\irefiev{112-01-30} \placeholder{C},
then \tcode{Q} is implicitly convertible from \placeholder{C}.
If the first argument is a named quantity,
then \tcode{Q} is of its kind\irefiev{112-01-04}.

\pnum
The member \tcode{character} represents
the set of the numerical value of \tcode{Q}\iref{qty.char.traits}
and is equal to
\begin{itemize}
\item
\tcode{Ch} if specified,
\item
otherwise, \tcode{quantity_character::real_scalar} for the first signature, and
\item
otherwise, \tcode{(BC).character},
where \tcode{BC} is the argument preceding \tcode{Ch} in the signatures above.
\end{itemize}

\pnum
\tcode{is_kind} specifies \tcode{Q} to start a new hierarchy tree of a kind.

\pnum
Optional arguments may appear in any order.

\pnum
\begin{example}
\begin{codeblock}
// The first signature defines a base quantity.
inline constexpr struct length final : quantity_spec<dim_length> {
} length;  // Length is a base quantity.

// The second signature defines a derived quantity.
inline constexpr struct area final : quantity_spec<pow<2>(length)> {
} area;  // An area equals length by length.

// The third and fourth signatures add a leaf to a hierarchy of kinds.
inline constexpr struct width final : quantity_spec<length> {
} width;  // Width is a kind of length.

// The fourth signature also refines the calculus required for implicit conversions.
inline constexpr struct angular_measure final :
    quantity_spec<dimensionless, arc_length / radius, is_kind> {
} angular_measure;  // Requires an arc length per radius, not just any quantity of dimension one.
\end{codeblock}
\end{example}

\rSec4[derived.qty]{Derived}

\indexlibraryglobal{derived_quantity_spec}
\begin{codeblock}
namespace mp_units {

template<@\defexposconceptnc{NamedQuantitySpec}@ Q>
using @\exposidnc{to-dimension}@ = decltype(auto(Q::dimension));  // \expos

template<typename... Expr>
struct @\exposidnc{derived-quantity-spec-impl}@ :                 // \expos
    @\exposidnc{quantity-spec-interface}@,
    @\exposidnc{expr-fractions}@<struct dimensionless, Expr...> {
  using @\exposidnc{base-type}@ = @\exposidnc{derived-quantity-spec-impl}@;
  using @\exposidnc{base}@ = @\exposidnc{expr-fractions}@<struct dimensionless, Expr...>;

  static constexpr @\libconcept{Dimension}@ auto dimension =
    @\exposidnc{expr-map}@<@\exposidnc{to-dimension}@, derived_dimension, struct dimension_one>(@\exposidnc{base}@{});
  static constexpr quantity_character character = @\seebelownc@;
};

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_quantity_spec final : @\exposidnc{derived-quantity-spec-impl}@<Expr...> {};

}
\end{codeblock}

\pnum
\tcode{derived_quantity_spec} is used by the library
to represent the result of a quantity calculus not equal to a named quantity.
\begin{example}
\begin{codeblock}
constexpr auto area = pow<2>(isq::length);
int x = area;  // error: cannot construct from \tcode{derived_quantity_spec<power<isq::length, 2>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_quantity_spec}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\pnum
Let
\begin{itemize}
\item
\tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{\exposidnc{base}::\exposidnc{nums}} and \tcode{\exposidnc{base}::\exposidnc{dens}}, respectively,
\item
\tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Pack)} be
\begin{codeblock}
std::max({quantity_character::real_scalar, @\exposidnc{expr-type}@<Pack>::character...})
\end{codeblock}
and
\item
\tcode{num_char} be \tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Nums)} and
\tcode{den_char} be \tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Dens)}.
\end{itemize}
The member \tcode{character} is equal to
\tcode{quantity_character::real_scalar} if \tcode{num_char == den_char} is \tcode{true}, and
\tcode{std::max(num_char, den_char)} otherwise.

\rSec4[dimless.qty]{Base quantity of dimension one}

\indexlibraryglobal{dimensionless}
\begin{codeblock}
namespace mp_units {

struct dimensionless final : quantity_spec<derived_quantity_spec<>> {};

}
\end{codeblock}

\pnum
\tcode{dimensionless} represents the base quantity of dimension one\irefiev{112-01-13}.

\rSec4[kind.of.qty]{Kind of}

\indexlibraryglobal{kind_of_}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{QuantitySpec}@ Q>
  requires(!@\exposconceptnc{QuantityKindSpec}@<Q>) && (@\exposidnc{get-kind-tree-root}@(Q{}) == Q{})
struct kind_of_ final : Q::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = kind_of_;                 // \expos
  static constexpr auto @\exposidnc{quantity-spec}@ = Q{};  // \expos
};

}
\end{codeblock}

\pnum
\tcode{kind_of<Q>} represents a kind of quantity\irefiev{112-01-04} \tcode{Q}.

\rSec3[qty.spec.utils]{Utilities}

\indexlibrarymemberexpos{QuantitySpec}{clone-kind-of}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto... From, @\libconcept{QuantitySpec}@ Q>
consteval @\libconcept{QuantitySpec}@ auto @\exposidnc{clone-kind-of}@(Q q);    // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr ((... && @\exposconceptnc{QuantityKindSpec}@<decltype(From)>))
  return kind_of<Q{}>;
else
  return q;
\end{codeblock}
\end{itemdescr}

\indexlibrarymemberexpos{QuantitySpec}{remove-kind}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval auto @\exposidnc{remove-kind}@(Q q);                   // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposconceptnc{QuantityKindSpec}@<Q>)
  return Q::@\exposidnc{quantity-spec}@;
else
  return q;
\end{codeblock}
\end{itemdescr}

\indexlibrarymemberexpos{QuantitySpec}{make-reference}
\indexlibrarymemberexpos{Unit}{make-reference}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ QS, @\libconcept{Unit}@ U>
  requires(!@\libconcept{AssociatedUnit}@<U>) || @\libconcept{UnitOf}@<U, QS{}>
consteval @\libconcept{Reference}@ auto @\exposidnc{make-reference}@(QS, U u);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { requires get_quantity_spec(U{}) == QS{}; })
  return u;
else
  return reference<QS, U>{};
\end{codeblock}
\end{itemdescr}

\rSec3[qty.spec.ops]{Operations}

\indexlibraryglobalexpos{quantity-spec-interface}
\begin{codeblock}
namespace mp_units {

struct @\exposidnc{quantity-spec-interface}@ {  // \expos
  template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
  friend consteval @\libconcept{QuantitySpec}@ auto operator*(Lhs lhs, Rhs rhs);

  template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
  friend consteval @\libconcept{QuantitySpec}@ auto operator/(Lhs lhs, Rhs rhs);

  template<typename Self, @\libconcept{UnitOf}@<Self{}> U>
  consteval @\libconcept{Reference}@ auto operator[](this Self self, U u);

  template<typename Self, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
    requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Q::quantity_spec, Self{}>
  constexpr @\libconcept{Quantity}@ auto operator()(this Self self, FwdQ&& q);

  template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
  friend consteval bool operator==(Lhs, Rhs);
};

}
\end{codeblock}

\indexlibrarymember{operator*}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator*(Lhs lhs, Rhs rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Lhs{}, Rhs{}>(@\exposidnc{expr-multiply}@<derived_quantity_spec, struct dimensionless>(
  @\exposidnc{remove-kind}@(lhs), @\exposidnc{remove-kind}@(rhs)))
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator/}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator/(Lhs lhs, Rhs rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Lhs{}, Rhs{}>(@\exposidnc{expr-divide}@<derived_quantity_spec, struct dimensionless>(
  @\exposidnc{remove-kind}@(lhs), @\exposidnc{remove-kind}@(rhs)))
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator[]}{QuantitySpec}
\begin{itemdecl}
template<typename Self, @\libconcept{UnitOf}@<Self{}> U>
consteval @\libconcept{Reference}@ auto operator[](this Self self, U u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{make-reference}(self, u)}.
\end{itemdescr}

\indexlibrarymember{operator()}{QuantitySpec}
\begin{itemdecl}
template<typename Self, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Q::quantity_spec, Self{}>
constexpr @\libconcept{Quantity}@ auto operator()(this Self self, FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, @\exposidnc{make-reference}@(self, Q::unit)}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator==}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}

\indexlibrarymember{inverse}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto inverse(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{dimensionless / q}.
\end{itemdescr}

\indexlibrarymember{pow}{QuantitySpec}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{QuantitySpec}@ Q>
  requires(Den != 0)
consteval @\libconcept{QuantitySpec}@ auto pow(Q q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Q{}>(
  @\exposidnc{expr-pow}@<Num, Den, derived_quantity_spec, struct dimensionless>(@\exposidnc{remove-kind}@(q)));
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{sqrt}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto sqrt(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(q)}.
\end{itemdescr}

\indexlibrarymember{cbrt}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto cbrt(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(q)}.
\end{itemdescr}

\rSec3[qty.spec.hier.algos]{Hierarchy algorithms}

\rSec4[qty.spec.conv]{Conversion}

\indexlibrarymember{implicitly_convertible}{QuantitySpec}
\begin{itemdecl}
consteval bool implicitly_convertible(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}

\indexlibrarymember{explicitly_convertible}{QuantitySpec}
\begin{itemdecl}
consteval bool explicitly_convertible(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}

\indexlibrarymember{castable}{QuantitySpec}
\begin{itemdecl}
consteval bool castable(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}

\indexlibrarymember{interconvertible}{QuantitySpec}
\begin{itemdecl}
consteval bool interconvertible(QuantitySpec auto qs1, QuantitySpec auto qs2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(qs1, qs2) \&\& implicitly_convertible(qs2, qs1)}.
\end{itemdescr}

\rSec4[qty.get.kind]{Get kind}

\indexlibrarymemberexpos{QuantitySpec}{get-kind-tree-root}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval @\libconcept{QuantitySpec}@ auto @\exposidnc{get-kind-tree-root}@(Q q);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{\exposconceptnc{QuantityKindSpec}<Q>} is \tcode{true},
returns \tcode{\exposidnc{remove-kind}(q)}.
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<Q, quantity_spec>()}
is \tcode{true}, and
the specialization of \tcode{Q::quantity_spec} has a template argument equal to \tcode{is_kind},
returns \tcode{q}.
\item
Otherwise, if \tcode{Q::\exposidnc{parent}} is a valid expression,
returns \tcode{\exposidnc{get-kind-tree-root}(Q::\exposidnc{parent})}.
\item
Otherwise, if \tcode{\exposconceptnc{DerivedQuantitySpec}<Q>} is \tcode{true},
returns
\begin{codeblock}
@\exposidnc{expr-map}@<@\exposidnc{to-kind}@, derived_quantity_spec, struct dimensionless>(q)
\end{codeblock}
where \exposid{to-kind} is defined as follows:
\begin{codeblock}
template<@\libconcept{QuantitySpec}@ Q>
using @\exposidnc{to-kind}@ = decltype(@\exposidnc{get-kind-tree-root}@(Q{}));  // \expos
\end{codeblock}
\item
Otherwise, returns \tcode{q}.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{get_kind}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval @\exposconceptnc{QuantityKindSpec}@ auto get_kind(Q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{kind_of<\exposidnc{get-kind-tree-root}(Q\{\})>}.
\end{itemdescr}

\rSec4[get.common.qty.spec]{Get common quantity specification}

\indexlibrarymember{get_common_quantity_spec}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto get_common_quantity_spec(@\libconcept{QuantitySpec}@ auto... qs)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{q1} be \tcode{qs...[0]},
\item
\tcode{q2} be \tcode{qs...[1]},
\item
\tcode{Q1} be \tcode{decltype(q1)},
\item
\tcode{Q2} be \tcode{decltype(q2)}, and
\item
\tcode{rest} be a pack denoting the elements of \tcode{qs} without \tcode{q1} and \tcode{q2}.
\end{itemize}

\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (sizeof...(qs) == 1)
  return q1;
else if constexpr (sizeof...(qs) == 2) {
  using QQ1 = decltype(@\exposidnc{remove-kind}@(q1));
  using QQ2 = decltype(@\exposidnc{remove-kind}@(q2));

  if constexpr (std::is_same_v<Q1, Q2>)
    return q1;
  else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@<Q1{}, Q2{}>)
    return QQ1{};
  else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@<Q2{}, Q1{}>)
    return QQ2{};
  else if constexpr ((@\exposconceptnc{QuantityKindSpec}@<Q1> && !@\exposconceptnc{QuantityKindSpec}@<Q2>) ||
                     (@\exposconceptnc{DerivedQuantitySpec}@<QQ1> && @\exposconceptnc{NamedQuantitySpec}@<QQ2> &&
                      implicitly_convertible(Q1{}, Q2{})))
    return q2;
  else if constexpr ((!@\exposconceptnc{QuantityKindSpec}@<Q1> && @\exposconceptnc{QuantityKindSpec}@<Q2>) ||
                     (@\exposconceptnc{NamedQuantitySpec}@<QQ1> && @\exposconceptnc{DerivedQuantitySpec}@<QQ2> &&
                      implicitly_convertible(Q2{}, Q1{})))
    return q1;
  else if constexpr (constexpr auto common_base = @\exposidnc{get-common-base}@<Q1{}, Q2{}>())
    return *common_base;
  else if constexpr (implicitly_convertible(Q1{}, Q2{}))
    return q2;
  else if constexpr (implicitly_convertible(Q2{}, Q1{}))
    return q1;
  else if constexpr (implicitly_convertible(@\exposidnc{get-kind-tree-root}@(Q1{}),
                                            @\exposidnc{get-kind-tree-root}@(Q2{})))
    return @\exposidnc{get-kind-tree-root}@(q2);
  else
    return @\exposidnc{get-kind-tree-root}@(q1);
} else
  return get_common_quantity_spec(get_common_quantity_spec(q1, q2), rest...);
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(sizeof...(qs) != 0 &&
 (sizeof...(qs) == 1 ||
  (sizeof...(qs) == 2 &&
   (@\exposconceptnc{QuantitySpecConvertibleTo}@<@\exposidnc{get-kind-tree-root}@(Q1{}), @\exposidnc{get-kind-tree-root}@(Q2{})> ||
    @\exposconceptnc{QuantitySpecConvertibleTo}@<@\exposidnc{get-kind-tree-root}@(Q2{}), @\exposidnc{get-kind-tree-root}@(Q1{})>)) ||
  requires { get_common_quantity_spec(get_common_quantity_spec(q1, q2), rest...); }))
\end{codeblock}
\end{itemdescr}

\rSec4[qty.get.common.base]{Get common base}

\pnum
In this subclause and \ref{qty.is.child.of},
let the kind of quantity\irefiev{112-01-04} hierarchy of \tcode{q} be the tuple
$h(\tcode{q}) = ( \tcode{q}, \tcode{q.par}, \tcode{q.par.par}, \ldots )$,
where \tcode{par} is \exposidnc{parent}.

\indexlibrarymemberexpos{QuantitySpec}{get-common-base}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto A, @\libconcept{QuantitySpec}@ auto B>
consteval auto @\exposidnc{get-common-base}@();  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
$a_s$ be the number of elements in $h(\tcode{A})$,
\item
$b_s$ be the number of elements in $h(\tcode{B})$,
\item
$s$ be $\operatorname{min}(a_s, b_s)$,
\item
$A$ be a tuple of the last $s$ elements of $h(\tcode{A})$, and
\item
$B$ be a tuple of the last $s$ elements of $h(\tcode{B})$.
\end{itemize}

\pnum
\effects
Looks for $x$, the first pair-wise equal element in $A$ and $B$.

\pnum
\returns
\tcode{std::optional($x$)}, if $x$ is found, and \tcode{std::optional<\unspec>()} otherwise.
\end{itemdescr}

\rSec4[qty.is.child.of]{Is child of}

\indexlibrarymemberexpos{QuantitySpec}{is-child-of}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Child, @\libconcept{QuantitySpec}@ Parent>
consteval bool @\exposidnc{is-child-of}@(Child ch, Parent p);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
If $h(\tcode{p})$ has more elements than $h(\tcode{ch})$, returns \tcode{false}.
Otherwise, let $C$ be a tuple of the last $s$ elements of $h(\tcode{ch})$,
where $s$ is the number of elements in $h(\tcode{p})$.
Returns \tcode{$C_0$ == p}.
\end{itemdescr}

\rSec2[qty.unit]{Unit}

\rSec3[qty.unit.general]{General}

\pnum
Subclause \ref{qty.unit} specifies the components
for defining a unit of measurement\irefiev{112-01-14}.

\rSec3[qty.unit.mag]{Magnitude}

\rSec4[qty.unit.mag.general]{General}

\pnum
Subclause \ref{qty.unit.mag} specifies the components
used to represent the numerical value\irefiev{112-01-29} of a unit
with support for powers\irefiev{102-02-08} of real numbers\irefiev{102-02-05}.

\rSec4[qty.unit.mag.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{MagConstant}@ = @\exposconceptnc{SymbolicConstant}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, mag_constant>();

template<typename T>
concept @\deflibconcept{UnitMagnitude}@ = (@\exposidnc{is-specialization-of}@<T, @\exposidnc{unit-magnitude}@>());

template<typename T>
concept @\defexposconceptnc{MagArg}@ = std::@\stdconcept{integral}@<T> || @\libconcept{MagConstant}@<T>;  // \expos
\end{itemdecl}

\rSec4[qty.unit.mag.types]{Types}

\indexlibraryglobal{mag_constant}
\begin{codeblock}
namespace mp_units {

template<symbol_text Symbol, long double Value>
  requires(Value > 0)
struct mag_constant {
  static constexpr auto @\exposidnc{symbol}@ = Symbol;       // \expos
  static constexpr long double @\exposidnc{value}@ = Value;  // \expos
};

}
\end{codeblock}

A specialization of \tcode{mag_constant} represents a real number\irefiev{102-02-05}.
\tcode{Symbol} is its symbol, and
\tcode{Value} is (an approximation of) its value.

\indexlibraryglobalexpos{unit-magnitude}
\begin{codeblock}
namespace mp_units {

template<auto... Ms>
struct @\exposidnc{unit-magnitude}@ {  // \expos
  // \ref{qty.unit.mag.ops}, operations

  template<@\libconcept{UnitMagnitude}@ M>
  friend consteval @\libconcept{UnitMagnitude}@ auto operator*(@\exposidnc{unit-magnitude}@ lhs, M rhs);

  friend consteval auto operator/(@\exposidnc{unit-magnitude}@ lhs, @\libconcept{UnitMagnitude}@ auto rhs);

  template<@\libconcept{UnitMagnitude}@ Rhs>
  friend consteval bool operator==(@\exposidnc{unit-magnitude}@, Rhs);

  template<int Num, int Den = 1>
  friend consteval auto @\exposidnc{pow}@(@\exposidnc{unit-magnitude}@);                         // \expos

  // \ref{qty.unit.mag.utils}, utilities

  friend consteval bool @\exposidnc{is-positive-integral-power}@(@\exposidnc{unit-magnitude}@);  // \expos

  template<auto... Ms2>
  friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@,             // \expos
                                         @\exposidnc{unit-magnitude}@<Ms2...>);
};

}
\end{codeblock}

\pnum
A specialization of \exposid{unit-magnitude}
represents the product of its template arguments.

\pnum
For the purposes of specifying the implementation-defined limits,
let the representation of the terms of \exposid{unit-magnitude} be the structure
\begin{codeblock}
struct {
  @\exposidnc{ratio}@ exp;
  @\exposidnc{base-type}@ base;
};
\end{codeblock}
representing the number $\tcode{base}^\tcode{exp}$,
where \exposid{base-type} is a model of \exposconcept{MagArg}.
\begin{itemize}
\item
There is a single term for each \exposid{base-type}.
\item
\tcode{exp.num} is not expanded into base.
\begin{note}
$2^3 = 8$ is not permitted.
\end{note}
\item
\tcode{exp.den} can reduce the base.
\begin{note}
$4^{1/2} = 2$ is permitted.
\end{note}
\item
If the result of an operation on \tcode{std::intmax_t} values is undefined,
the behavior is
\impldef{behavior of \exposid{unit-magnitude} operations that do not fit in a \tcode{std::intmax_t}}.
\end{itemize}

\rSec4[qty.unit.mag.ops]{Operations}

\indexlibrarymember{operator*}{UnitMagnitude}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M>
friend consteval @\libconcept{UnitMagnitude}@ auto operator*(@\exposidnc{unit-magnitude}@ lhs, M rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{sizeof...(Ms) == 0} is \tcode{true}, returns \tcode{rhs}.
\item
Otherwise, if \tcode{std::is_same_v<M, \exposidnc{unit-magnitude}<>>}, returns \tcode{lhs}.
\item
Otherwise, returns an unspecified value equal to $\tcode{lhs} \times \tcode{rhs}$.
\end{itemize}
\end{itemdescr}

\indexlibrarymember{operator/}{UnitMagnitude}
\begin{itemdecl}
friend consteval auto operator/(@\exposidnc{unit-magnitude}@ lhs, @\libconcept{UnitMagnitude}@ auto rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{lhs * \exposid{pow}<-1>(rhs)}.
\end{itemdescr}

\indexlibrarymember{operator==}{UnitMagnitude}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ Rhs>
friend consteval bool operator==(@\exposidnc{unit-magnitude}@, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<\exposidnc{unit-magnitude}, Rhs>}.
\end{itemdescr}

\indexlibrarymemberexpos{UnitMagnitude}{pow}
\begin{itemdecl}
template<int Num, int Den = 1>
friend consteval auto @\exposidnc{pow}@(@\exposidnc{unit-magnitude}@ base);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{Num == 0} is \tcode{true}, returns \tcode{\exposidnc{unit-magnitude}<>\{\}}.
\item
Otherwise, returns an unspecified value equal to $\tcode{base}^{\tcode{Num}/\tcode{Den}}$.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{mag}
\begin{itemdecl}
template<@\exposconceptnc{MagArg}@ auto V>
constexpr @\libconcept{UnitMagnitude}@ auto mag = @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\tcode{V} is greater than $0$.

\pnum
\effects
If \tcode{\libconcept{MagConstant}<decltype(V)>} is satisfied,
initializes \tcode{mag} with \tcode{\exposidnc{unit-magnitude}<V>\{\}}.
Otherwise, initializes \tcode{mag} with
an unspecified value equal to \tcode{V}.
\end{itemdescr}

\indexlibraryglobal{mag_ratio}
\begin{itemdecl}
template<std::intmax_t N, std::intmax_t D>
  requires(N > 0)
constexpr @\libconcept{UnitMagnitude}@ auto mag_ratio = @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \tcode{mag_ratio} with
an unspecified value equal to $\tcode{N}/\tcode{D}$.
\end{itemdescr}

\indexlibraryglobal{mag_power}
\begin{itemdecl}
template<@\exposconceptnc{MagArg}@ auto Base, int Num, int Den = 1>
constexpr @\libconcept{UnitMagnitude}@ auto mag_power = @\exposidnc{pow}@<Num, Den>(mag<Base>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\constraints
\tcode{Base} is greater than $0$.
\end{itemdescr}

\rSec4[qty.unit.mag.utils]{Utilities}

\indexlibrarymemberexpos{UnitMagnitude}{is-positive-integral-power}
\begin{itemdecl}
friend consteval bool @\exposidnc{is-positive-integral-power}@(@\exposidnc{unit-magnitude}@ x);              // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{false} if \tcode{x} has a negative or rational exponent, and
\tcode{true} otherwise.
\end{itemdescr}

\indexlibrarymemberexpos{UnitMagnitude}{common-magnitude}
\begin{itemdecl}
template<auto... Ms2>
friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, @\exposidnc{unit-magnitude}@<Ms2...>);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
The largest magnitude \tcode{C}
such that each input magnitude is expressible
by only positive powers relative to \tcode{C}.
\end{itemdescr}

\rSec3[qty.unit.traits]{Traits}

\indexlibraryglobal{space_before_unit_symbol}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto U>
constexpr bool space_before_unit_symbol = true;
\end{itemdecl}

\begin{itemdescr}
\pnum
The formatting functions\iref{qty.unit.sym.fmt} use \tcode{space_before_unit_symbol}
to determine whether there is a space
between the numerical value and the unit symbol.

\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize \tcode{space_before_unit_symbol}
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.
\end{itemdescr}

\rSec3[qty.unit.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Unit}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{unit-interface}@>;

template<typename T>
concept @\deflibconcept{PrefixableUnit}@ = @\libconcept{Unit}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, named_unit>();

template<typename T>
concept @\deflibconcept{AssociatedUnit}@ = @\libconcept{Unit}@<U> && @\exposidnc{has-associated-quantity}@(U{});

template<typename U, auto QS>
concept @\deflibconcept{UnitOf}@ = @\libconcept{AssociatedUnit}@<U> && @\libconcept{QuantitySpec}@<decltype(QS)> &&
                 @\exposconceptnc{QuantitySpecConvertibleTo}@<get_quantity_spec(U{}), QS> &&
                 (get_kind(QS) == get_kind(get_quantity_spec(U{})) ||
                  !@\exposconceptnc{NestedQuantityKindSpecOf}@<get_quantity_spec(U{}), QS>);

template<auto From, auto To>
concept @\defexposconceptnc{UnitConvertibleTo}@ =                                     // \expos
  @\libconcept{Unit}@<decltype(From)> && @\libconcept{Unit}@<decltype(To)> && (convertible(From, To));

template<typename U, auto FromU, auto QS>
concept @\defexposconceptnc{UnitCompatibleWith}@ =                                    // \expos
  @\libconcept{Unit}@<U> && @\libconcept{Unit}@<decltype(FromU)> && @\libconcept{QuantitySpec}@<decltype(QS)> &&
  (!@\libconcept{AssociatedUnit}@<U> || @\libconcept{UnitOf}@<U, QS>) && @\exposconceptnc{UnitConvertibleTo}@<FromU, U{}>;

template<typename T>
concept @\defexposconceptnc{OffsetUnit}@ = @\libconcept{Unit}@<T> && requires { T::@\exposidnc{point-origin}@; };  // \expos

template<typename From, typename To>
concept @\defexposconceptnc{PotentiallyConvertibleTo}@ =                              // \expos
  @\libconcept{Unit}@<From> && @\libconcept{Unit}@<To> &&
  ((@\libconcept{AssociatedUnit}@<From> && @\libconcept{AssociatedUnit}@<To> &&
    implicitly_convertible(get_quantity_spec(From{}), get_quantity_spec(To{}))) ||
   (!@\libconcept{AssociatedUnit}@<From> && !@\libconcept{AssociatedUnit}@<To>));
\end{itemdecl}

\rSec3[qty.unit.types]{Types}

\rSec4[qty.canon.unit]{Canonical}

\indexlibraryglobalexpos{canonical-unit}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
struct @\exposidnc{canonical-unit}@ {  // \expos
  M mag;
  U reference_unit;
};

}
\end{codeblock}

\pnum
\exposid{canonical-unit} represents a unit expressed in terms of base units\irefiev{112-01-18}.
\begin{note}
Other types representing units are equal only if they have the same type.
\exposid{canonical-unit} is used to implement binary relations other than equality.
\end{note}
\tcode{reference_unit} is simplified\iref{qty.sym.expr.algos}.

\indexlibrarymemberexpos{Unit}{get-canonical-unit}
\begin{itemdecl}
consteval auto @\exposidnc{get-canonical-unit}@(@\libconcept{Unit}@ auto u);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
The instantiation of \exposid{canonical-unit} for \tcode{u}.
\end{itemdescr}

\rSec4[qty.scaled.unit]{Scaled}

\indexlibraryglobal{scaled_unit}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{UnitMagnitude}@ auto M, @\libconcept{Unit}@ U>
  requires(M != @\exposidnc{unit-magnitude}@<>{} && M != mag<1>)
struct scaled_unit final : @\exposidnc{unit-interface}@ {
  using @\exposidnc{base-type}@ = scaled_unit;                         // \expos
  static constexpr @\libconcept{UnitMagnitude}@ auto @\exposidnc{mag}@ = M;           // \expos
  static constexpr U @\exposidnc{reference-unit}@{};                   // \expos
  static constexpr auto @\exposidnc{point-origin}@ = U::point_origin;  // \expos, present only
    // if the \fakegrammarterm{qualified-id} \tcode{U::point_origin} is valid and denotes an object
};

}
\end{codeblock}

\pnum
\tcode{scaled_unit<M, U>} is used by the library
to represent the unit $\tcode{M} \times \tcode{U}$.

\rSec4[qty.named.unit]{Named}

\indexlibraryglobal{named_unit}
\begin{codeblock}
namespace mp_units {

template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS>
  requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@<decltype(auto(QS.dimension))>
struct named_unit<Symbol, QS> : @\exposidnc{unit-interface}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
  static constexpr auto @\exposidnc{quantity-spec}@ = QS;  // \expos
};

template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS, @\libconcept{PointOrigin}@ auto PO>
  requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@<decltype(auto(QS.dimension))>
struct named_unit<Symbol, QS, PO> : @\exposidnc{unit-interface}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
  static constexpr auto @\exposidnc{quantity-spec}@ = QS;  // \expos
  static constexpr auto @\exposidnc{point-origin}@ = PO;   // \expos
};

template<symbol_text Symbol>
  requires(!Symbol.empty())
struct named_unit<Symbol> : @\exposidnc{unit-interface}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
};

template<symbol_text Symbol, @\libconcept{Unit}@ auto U>
  requires(!Symbol.empty())
struct named_unit<Symbol, U> : decltype(U)::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
};

template<symbol_text Symbol, @\libconcept{Unit}@ auto U, @\libconcept{PointOrigin}@ auto PO>
  requires(!Symbol.empty())
struct named_unit<Symbol, U, PO> : decltype(U)::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
  static constexpr auto @\exposidnc{point-origin}@ = PO;   // \expos
};

template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS>
  requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension)
struct named_unit<Symbol, U, QS> : decltype(U)::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
  static constexpr auto @\exposidnc{quantity-spec}@ = QS;  // \expos
};

template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS,
         @\libconcept{PointOrigin}@ auto PO>
  requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension)
struct named_unit<Symbol, U, QS, PO> : decltype(U)::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = named_unit;              // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol;     // \expos
  static constexpr auto @\exposidnc{quantity-spec}@ = QS;  // \expos
  static constexpr auto @\exposidnc{point-origin}@ = PO;   // \expos
};

}
\end{codeblock}

\pnum
A \defnadj{named}{unit} is a type that models \libconcept{PrefixableUnit}.
A specialization of \tcode{named_unit} is used as a base type when defining a named unit.

\pnum
In the following descriptions, let \tcode{U} be a named unit defined with an alluded signature.
The identifier of \tcode{U} represents
its unit name\irefiev{112-01-15}
or special unit name\irefiev{112-01-16}.
\tcode{Symbol} is its unit symbol\irefiev{112-01-17}.

\pnum
The possible arguments to \tcode{named_unit} are
\begin{itemize}
\item
$(\text{the unit symbol}, \text{a kind of base quantity}, \opt{\text{a point origin}})$,
\item
$(\text{the unit symbol})$,
\item
$(\text{the unit symbol}, \text{a unit expression}, \opt{\text{a point origin}})$, and
\item
$(\text{the unit symbol}, \text{a unit expression}, \text{a kind of quantity}, \opt{\text{a point origin}})$.
\end{itemize}

\pnum
The first signature defines the unit of a base quantity
without a unit prefix\irefiev{112-01-26}.
The second signature defines a unit
that can be reused by several base quantities.
The third and fourth signatures with a unit expression argument \placeholder{E}
define \tcode{U} as implicitly convertible from \placeholder{E}.
The first and fourth signatures with a kind of quantity\irefiev{112-01-04} \placeholder{Q}
also restrict \tcode{U} to \placeholder{Q}.

\pnum
A point origin argument specifies the default point origin of \tcode{U}\iref{qty.pt.syn}.

\pnum
\begin{example}
\begin{codeblock}
// The first signature defines a base unit restricted to a kind of base quantity.
inline constexpr struct second final : named_unit<"s", kind_of<time>> {
} second;

// The third and fourth signatures give a name to the unit argument.
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {
} minute;  // $\txtrm{min} = 60 \txtrm{ s}$.

// The fourth signature also further restricts the kind of quantity.
inline constexpr struct hertz final : named_unit<"Hz", inverse(second), kind_of<frequency>> {
} hertz;  // $\txtrm{Hz}$ can't measure becquerel, activity,
          // or any other quantity with dimension $\txtrm{T}^{-1}$
          // that isn't a kind of frequency.
\end{codeblock}
\end{example}

\rSec4[qty.prefixed.unit]{Prefixed}

\indexlibraryglobal{prefixed_unit}
\begin{codeblock}
namespace mp_units {

template<symbol_text Symbol, @\libconcept{UnitMagnitude}@ auto M, @\libconcept{PrefixableUnit}@ auto U>
  requires(!Symbol.empty())
struct prefixed_unit : decltype(M * U)::@\exposidnc{base-type}@ {
  using @\exposidnc{base-type}@ = prefixed_unit;                   // \expos
  static constexpr auto @\exposidnc{symbol}@ = Symbol + U.@\exposidnc{symbol}@;  // \expos
};

}
\end{codeblock}

\pnum
\tcode{prefixed_unit<Symbol, M, U>} represents the unit \tcode{U} with a unit prefix\irefiev{112-01-26}.
\tcode{Symbol} is the symbol of the unit prefix.
\tcode{M} is the factor of the unit prefix.
A specialization of \tcode{prefixed_unit} is used as a base type when defining a unit prefix.
\begin{example}
\begin{codeblock}
template<@\libconcept{PrefixableUnit}@ auto U>
struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {};

template<@\libconcept{PrefixableUnit}@ auto U>
constexpr kilo_<U> kilo;

inline constexpr auto kilogram = kilo<si::gram>;
\end{codeblock}
\end{example}

\rSec4[qty.common.unit]{Common}

\indexlibraryglobal{common_unit}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
struct common_unit final : decltype(@\exposidnc{get-common-scaled-unit}@(U1{}, U2{}, Rest{}...))::@\exposidnc{base-type}@
{
  using @\exposidnc{base-type}@ = common_unit;       // \expos
  static constexpr auto @\exposidnc{common-unit}@ =  // \expos
    @\exposidnc{get-common-scaled-unit}@(U1{}, U2{}, Rest{}...);
};

}
\end{codeblock}

\pnum
\tcode{common_unit} is used by the library
to encapsulate a conversion factor between units\irefiev{112-01-33}
common to the operands of quantity addition.
\begin{example}
The result of \tcode{1 * km + 1 * mi}
has a common unit $[8/125] \txtrm{ m}$
encapsulated by \tcode{common_unit<mi, km>}.
\end{example}
A program that instantiates a specialization of \tcode{common_unit}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\begin{itemdecl}
template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
consteval @\libconcept{Unit}@ auto @\exposidnc{get-common-scaled-unit}@(U1, U2, Rest... rest)  // \expos
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
constexpr auto res = [] {
  constexpr auto canonical_lhs = @\exposidnc{get-canonical-unit}@(U1{});
  constexpr auto canonical_rhs = @\exposidnc{get-canonical-unit}@(U2{});
  constexpr auto common_mag = @\exposidnc{common-magnitude}@(canonical_lhs.mag, canonical_rhs.mag);
  if constexpr (common_mag == mag<1>)
    return canonical_lhs.reference_unit;
  else
    return scaled_unit<common_mag, decltype(auto(canonical_lhs.reference_unit))>{};
}();
if constexpr (sizeof...(rest) == 0)
  return res;
else
  return @\exposidnc{get-common-scaled-unit}@(res, rest...);
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(U1{}, U2{}) && (sizeof...(Rest) == 0 || requires {
   @\exposidnc{get-common-scaled-unit}@(@\exposidnc{get-common-scaled-unit}@(u1, u2), rest...);
 }))
\end{codeblock}
\end{itemdescr}

\rSec4[qty.derived.unit]{Derived}

\indexlibraryglobal{derived_unit}
\begin{codeblock}
namespace mp_units {

template<typename... Expr>
struct @\exposidnc{derived-unit-impl}@ :              // \expos
    @\exposidnc{unit-interface}@,
    @\exposidnc{expr-fractions}@<struct one, Expr...> {
  using @\exposidnc{base-type}@ = @\exposidnc{derived-unit-impl}@;  // \expos
};

template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_unit final : @\exposidnc{derived-unit-impl}@<Expr...> {};

}
\end{codeblock}

\pnum
\tcode{derived_unit} is used by the library
to represent a derived unit\irefiev{112-01-19}.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
int x = m * m;  // error: cannot construct from \tcode{derived_unit<power<si::metre, 2>>}
int y = m * s;  // error: cannot construct from \tcode{derived_unit<si::metre, si::second>}
int z = m / s;  // error: cannot construct from \tcode{derived_unit<si::metre, per<si::second>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_unit}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.

\rSec4[qty.unit.one]{One}

\indexlibraryglobal{one}
\begin{codeblock}
namespace mp_units {

struct one final : @\exposidnc{derived-unit-impl}@<> {};

}
\end{codeblock}

\pnum
\tcode{one} represents the base unit\irefiev{112-01-18} of a quantity of dimension one\irefiev{112-01-13}.

\rSec3[qty.unit.ops]{Operations}

\indexlibraryglobalexpos{unit-interface}
\begin{codeblock}
namespace mp_units {

struct @\exposidnc{unit-interface}@ {  // \expos
  template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
  friend consteval @\libconcept{Unit}@ auto operator*(M, U u);

  friend consteval @\libconcept{Unit}@ auto operator*(@\libconcept{Unit}@ auto, @\libconcept{UnitMagnitude}@ auto) = delete;

  template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
  friend consteval @\libconcept{Unit}@ auto operator/(M mag, U u);

  template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
  friend consteval @\libconcept{Unit}@ auto operator*(Lhs lhs, Rhs rhs);

  template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
  friend consteval @\libconcept{Unit}@ auto operator/(Lhs lhs, Rhs rhs);

  // \ref{qty.unit.cmp}, comparison

  template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
  friend consteval bool operator==(Lhs, Rhs);

  template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
  friend consteval bool equivalent(Lhs lhs, Rhs rhs);
};

}
\end{codeblock}

\indexlibrarymember{operator*}{UnitMagnitude}
\indexlibrarymember{operator*}{Unit}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator*(M, U u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<M, decltype(auto(mag<1>))>)
  return u;
else if constexpr (@\exposidnc{is-specialization-of}@<U, scaled_unit>()) {
  if constexpr (M{} * U::@\exposidnc{mag}@ == mag<1>)
    return U::@\exposidnc{reference-unit}@;
  else
    return scaled_unit<M{} * U::@\exposidnc{mag}@, decltype(auto(U::@\exposidnc{reference-unit}@))>{};
} else
  return scaled_unit<M{}, U>{};
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
friend consteval @\libconcept{Unit}@ auto operator*(@\libconcept{Unit}@ auto, @\libconcept{UnitMagnitude}@ auto) = delete;
\end{itemdecl}

\begin{itemdescr}
\pnum
\recommended
Suggest swapping the operands.
\end{itemdescr}

\indexlibrarymember{operator/}{UnitMagnitude}
\indexlibrarymember{operator/}{Unit}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator/(M mag, U u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{mag * inverse(u)}.
\end{itemdescr}

\indexlibrarymember{operator*}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator*(Lhs lhs, Rhs rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-multiply}<derived_unit, struct one>(lhs, rhs)}.
\end{itemdescr}

\indexlibrarymember{operator/}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator/(Lhs lhs, Rhs rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-divide}<derived_unit, struct one>(lhs, rhs)}.
\end{itemdescr}

\indexlibrarymember{inverse}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto inverse(@\libconcept{Unit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{one / u}.
\end{itemdescr}

\indexlibrarymember{pow}{Unit}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Unit}@ U>
  requires(Den != 0)
consteval @\libconcept{Unit}@ auto pow(U u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-pow}<Num, Den, derived_unit, struct one>(u)}.
\end{itemdescr}

\indexlibrarymember{sqrt}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto sqrt(@\libconcept{Unit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(u)}.
\end{itemdescr}

\indexlibrarymember{cbrt}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto cbrt(@\libconcept{Unit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(u)}.
\end{itemdescr}

\indexlibrarymember{square}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto square(@\libconcept{Unit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<2>(u)}.
\end{itemdescr}

\indexlibrarymember{cubic}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto cubic(@\libconcept{Unit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{pow<3>(u)}.
\end{itemdescr}

\rSec3[qty.unit.cmp]{Comparison}

\indexlibrarymember{operator==}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}

\indexlibrarymember{equivalent}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool equivalent(Lhs lhs, Rhs rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
const auto lhs_canonical = @\exposidnc{get-canonical-unit}@(lhs);
const auto rhs_canonical = @\exposidnc{get-canonical-unit}@(rhs);
return lhs_canonical.mag == rhs_canonical.mag &&
       lhs_canonical.reference_unit == rhs_canonical.reference_unit;
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{convertible}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ From, @\libconcept{Unit}@ To>
consteval bool convertible(From from, To to);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<From, To>)
  return true;
else if constexpr (@\exposconceptnc{PotentiallyConvertibleTo}@<From, To>)
  return std::is_same_v<decltype(@\exposidnc{get-canonical-unit}@(from).reference_unit),
                        decltype(@\exposidnc{get-canonical-unit}@(to).reference_unit)>;
else
  return false;
\end{codeblock}
\end{itemdescr}

\rSec3[qty.unit.obs]{Observers}

\indexlibrarymember{get_quantity_spec}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(@\libconcept{AssociatedUnit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{kind_of<\exposidnc{get-associated-quantity}(u)>}.
\end{itemdescr}

\indexlibrarymember{get_unit}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto get_unit(@\libconcept{AssociatedUnit}@ auto u);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{u}.
\end{itemdescr}

\indexlibrarymember{get_common_unit}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto get_common_unit(@\libconcept{Unit}@ auto... us)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{u1} be \tcode{us...[0]},
\item
\tcode{u2} be \tcode{us...[1]},
\item
\tcode{U1} be \tcode{decltype(u1)},
\item
\tcode{U2} be \tcode{decltype(u2)}, and
\item
\tcode{rest} be a pack denoting the elements of \tcode{us} without \tcode{u1} and \tcode{u2}.
\end{itemize}

\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (sizeof...(us) == 1)
  return u1;
else if constexpr (sizeof...(us) == 2) {
  if constexpr (@\exposidnc{is-derived-from-specialization-of}@<U1, common_unit>()) {
    return @\textit{TBD.}@;
  } else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<U2, common_unit>())
    return get_common_unit(u2, u1);
  else if constexpr (std::is_same_v<U1, U2>)
    return u1;
  else if constexpr (equivalent(U1{}, U2{})) {
    if constexpr (std::@\stdconcept{derived_from}@<U1, typename U2::@\exposidnc{base-type}@>)
      return u1;
    else if constexpr (std::@\stdconcept{derived_from}@<U2, typename U1::@\exposidnc{base-type}@>)
      return u2;
    else
      return std::conditional_t<@\exposidnc{type-less-impl}@<U1, U2>(), U1, U2>{};
  } else {
    constexpr auto canonical_lhs = @\exposidnc{get-canonical-unit}@(U1{});
    constexpr auto canonical_rhs = @\exposidnc{get-canonical-unit}@(U2{});

    if constexpr (@\exposidnc{is-positive-integral-power}@(canonical_lhs.mag / canonical_rhs.mag))
      return u2;
    else if constexpr (@\exposidnc{is-positive-integral-power}@(canonical_rhs.mag / canonical_lhs.mag))
      return u1;
    else {
      if constexpr (@\exposidnc{type-less}@<U1, U2>{})
        return common_unit<U1, U2>{};
      else
        return common_unit<U2, U1>{};
    }
  }
} else
  return get_common_unit(get_common_unit(u1, u2), rest...);
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(sizeof...(us) != 0 && (sizeof...(us) == 1 ||  //
                        (sizeof...(us) == 2 && convertible(U1{}, U2{})) ||
                        requires { get_common_unit(get_common_unit(u1, u2), rest...); }))
\end{codeblock}
\end{itemdescr}

\rSec3[assoc.qty]{Associated quantity}

\indexlibrarymemberexpos{Unit}{has-associated-quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ U>
consteval bool @\exposidnc{has-associated-quantity}@(U);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{U::\exposidnc{quantity-spec}} is a valid expression,
returns \tcode{true}.
\item
Otherwise, if \tcode{U::\exposidnc{reference-unit}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{has-associated-quantity}@(U::@\exposidnc{reference-unit}@)
\end{codeblock}
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<U, \exposidnc{expr-fractions}>()}
is \tcode{true},
let \tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{U::\exposidnc{nums}} and \tcode{U::\exposidnc{dens}}, respectively.
Returns
\begin{codeblock}
(... && @\exposidnc{has-associated-quantity}@(@\exposidnc{expr-type}@<Nums>{})) &&
  (... && @\exposidnc{has-associated-quantity}@(@\exposidnc{expr-type}@<Dens>{}))
\end{codeblock}
\item
Otherwise, returns \tcode{false}.
\end{itemize}
\end{itemdescr}

\indexlibrarymemberexpos{AssociatedUnit}{get-associated-quantity}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U>
consteval auto @\exposidnc{get-associated-quantity}@(U u);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{U} is of the form \tcode{common_unit<Us...>},
returns
\begin{codeblock}
get_common_quantity_spec(@\exposidnc{get-associated-quantity}@(Us{})...)
\end{codeblock}
\item
Otherwise, if \tcode{U::\exposidnc{quantity-spec}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{remove-kind}@(U::@\exposidnc{quantity-spec}@)
\end{codeblock}
\item
Otherwise, if \tcode{U::\exposidnc{reference-unit}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{get-associated-quantity}@(U::@\exposidnc{reference-unit}@)
\end{codeblock}
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<U, \exposidnc{expr-fractions}>()}
is \tcode{true},
returns
\begin{codeblock}
@\exposidnc{expr-map}@<@\exposidnc{to-quantity-spec}@, derived_quantity_spec, struct dimensionless>(u)
\end{codeblock}
where \exposid{to-quantity-spec} is defined as follows:
\begin{codeblock}
template<@\libconcept{AssociatedUnit}@ U>
using @\exposidnc{to-quantity-spec}@ = decltype(@\exposidnc{get-associated-quantity}@(U{}));  // \expos
\end{codeblock}
\end{itemize}
\end{itemdescr}

\rSec3[qty.unit.sym.fmt]{Symbol formatting}

\indexlibrarymember{unit_symbol_to}{Unit}
\begin{itemdecl}
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Unit}@ U>
constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {});
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
TBD.

\pnum
\returns
TBD.
\end{itemdescr}

\indexlibrarymember{unit_symbol}{Unit}
\begin{itemdecl}
template<unit_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Unit}@ U>
consteval std::string_view unit_symbol(U);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
TBD.
\end{codeblock}
\end{itemdescr}

\rSec2[qty.ref.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Reference}@ = @\libconcept{AssociatedUnit}@<T> || (@\exposidnc{is-specialization-of}@<T, reference>());
\end{itemdecl}

A type \tcode{T} that satisfies \tcode{Reference}
represents the reference of a quantity\irefiev{112-01-01}.

\begin{itemdecl}
template<typename T, auto QS>
concept @\deflibconcept{ReferenceOf}@ = @\libconcept{Reference}@<T> && @\libconcept{QuantitySpecOf}@<decltype(get_quantity_spec(T{})), QS>;
\end{itemdecl}

\rSec2[qty.ref.syn]{Class template \tcode{reference}}

\indexlibrarymember{operator*}{reference}
\indexlibrarymember{operator*}{AssociatedUnit}
\indexlibrarymember{operator/}{reference}
\indexlibrarymember{operator/}{AssociatedUnit}
\indexlibrarymember{inverse}{reference}
\indexlibrarymember{pow}{reference}
\indexlibrarymember{sqrt}{reference}
\indexlibrarymember{cbrt}{reference}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{QuantitySpec}@ auto Q, @\libconcept{Unit}@ auto U>
using @\exposidnc{reference-t}@ = reference<decltype(Q), decltype(U)>;  // \expos

template<@\libconcept{QuantitySpec}@ Q, @\libconcept{Unit}@ U>
struct @\libglobal{reference}@ {
  // \ref{qty.ref.ops}, operations

  template<typename Q2, typename U2>
  friend consteval auto operator*(reference, reference<Q2, U2>)
    -> @\exposidnc{reference-t}@<Q{} * Q2{}, U{} * U2{}>;

  template<@\libconcept{AssociatedUnit}@ U2>
  friend consteval auto operator*(reference, U2)
    -> @\exposidnc{reference-t}@<Q{} * get_quantity_spec(U2{}), U{} * U2{}>;

  template<@\libconcept{AssociatedUnit}@ U1>
  friend consteval auto operator*(U1, reference)
    -> @\exposidnc{reference-t}@<get_quantity_spec(U1{}) * Q{}, U1{} * U{}>;

  template<typename Q2, typename U2>
  friend consteval auto operator/(reference, reference<Q2, U2>)
    -> @\exposidnc{reference-t}@<Q{} / Q2{}, U{} / U2{}>;

  template<@\libconcept{AssociatedUnit}@ U2>
  friend consteval auto operator/(reference, U2)
    -> @\exposidnc{reference-t}@<Q{} / get_quantity_spec(U2{}), U{} / U2{}>;

  template<@\libconcept{AssociatedUnit}@ U1>
  friend consteval auto operator/(U1, reference)
    -> @\exposidnc{reference-t}@<get_quantity_spec(U1{}) / Q{}, U1{} / U{}>;

  friend consteval auto inverse(reference) -> @\exposidnc{reference-t}@<inverse(Q{}), inverse(U{})>;

  template<std::intmax_t Num, std::intmax_t Den = 1>
    requires(Den != 0)
  friend consteval auto pow(reference) -> @\exposidnc{reference-t}@<pow<Num, Den>(Q{}), pow<Num, Den>(U{})>;
  friend consteval auto sqrt(reference) -> @\exposidnc{reference-t}@<sqrt(Q{}), sqrt(U{})>;
  friend consteval auto cbrt(reference) -> @\exposidnc{reference-t}@<cbrt(Q{}), cbrt(U{})>;

  // \ref{qty.ref.cmp}, comparison

  template<typename Q2, typename U2>
  friend consteval bool operator==(reference, reference<Q2, U2>);

  template<@\libconcept{AssociatedUnit}@ U2>
  friend consteval bool operator==(reference, U2 u2);

  template<typename Q2, typename U2>
  friend consteval bool convertible(reference, reference<Q2, U2>);

  template<@\libconcept{AssociatedUnit}@ U2>
  friend consteval bool convertible(reference, U2 u2);

  template<@\libconcept{AssociatedUnit}@ U1>
  friend consteval bool convertible(U1 u1, reference);
};

}
\end{codeblock}

\pnum
\tcode{reference<Q, U>} represents the reference of a quantity\irefiev{112-01-01}.
The unit of measurement \tcode{U}\irefiev{112-01-14}
is used to measure a value of the quantity \tcode{Q}\irefiev{112-01-28}.
\begin{note}
\tcode{reference} is typically implicitly instantiated
when specifying that a unit measures a more specific quantity.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
auto x = 1 * m;                 // measures a length
auto y = 1 * isq::width[m];     // measures a width
auto z = 1 * isq::diameter[m];  // measures a diameter
\end{codeblock}
\end{example}
\end{note}

\rSec2[qty.ref.ops]{Operations}

\pnum
Each member function with a \fakegrammarterm{trailing-return-type}
of \tcode{-> \exposidnc{reference-t}<T...>}
returns \tcode{\{\}}.

\indexlibrarymember{operator*}{Representation}
\indexlibrarymember{operator*}{Reference}
\begin{itemdecl}
template<typename FwdRep, @\libconcept{Reference}@ R,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), r\};}
\end{itemdescr}

\indexlibrarymember{operator*}{Representation}
\indexlibrarymember{operator*}{Reference}
\begin{itemdecl}
template<typename FwdRep, @\libconcept{Reference}@ R,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr @\libconcept{Quantity}@ auto operator/(FwdRep&& lhs, R);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), inverse(R\{\})\};}
\end{itemdescr}

\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator*}{Reference}
\indexlibrarymember{operator/}{quantity}
\indexlibrarymember{operator/}{Reference}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator*(FwdQ&& q, R);
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator/(FwdQ&& q, R);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, Q::reference @\atsign@ R{}};
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
template<@\libconcept{Reference}@ R, typename Rep>
  requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator*(R, Rep&&) = delete;

template<@\libconcept{Reference}@ R, typename Rep>
  requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator/(R, Rep&&) = delete;

template<@\libconcept{Reference}@ R, typename Q>
  requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator*(R, Q&&) = delete;

template<@\libconcept{Reference}@ R, typename Q>
  requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator/(R, Q&&) = delete;
\end{itemdecl}

\begin{itemdescr}
\pnum
\recommended
Suggest swapping the operands.
\end{itemdescr}

\rSec2[qty.ref.cmp]{Comparison}

\indexlibrarymember{operator==}{reference}
\begin{itemdecl}
template<typename Q2, typename U2>
friend consteval bool operator==(reference, reference<Q2, U2>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\} == Q2\{\} \&\& U\{\} == U2\{\}}.
\end{itemdescr}

\indexlibrarymember{operator==}{reference}
\indexlibrarymember{operator==}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool operator==(reference, U2 u2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\} == get_quantity_spec(u2) \&\& U\{\} == u2}.
\end{itemdescr}

\indexlibrarymember{convertible}{reference}
\begin{itemdecl}
template<typename Q2, typename U2>
friend consteval bool convertible(reference, reference<Q2, U2>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(Q\{\}, Q2\{\}) \&\& convertible(U\{\}, U2\{\})}.
\end{itemdescr}

\indexlibrarymember{convertible}{reference}
\indexlibrarymember{convertible}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool convertible(reference, U2 u2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(Q\{\}, get_quantity_spec(u2)) \&\& convertible(U\{\}, u2)}.
\end{itemdescr}

\indexlibrarymember{convertible}{reference}
\indexlibrarymember{convertible}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U1>
friend consteval bool convertible(U1 u1, reference);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(get_quantity_spec(u1), Q\{\}) \&\& convertible(u1, U\{\})}.
\end{itemdescr}

\rSec2[qty.ref.obs]{Observers}

\indexlibrarymember{get_quantity_spec}{reference}
\begin{itemdecl}
template<typename Q, typename U>
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(reference<Q, U>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\}}.
\end{itemdescr}

\indexlibrarymember{get_unit}{reference}
\begin{itemdecl}
template<typename Q, typename U>
consteval @\libconcept{Unit}@ auto get_unit(reference<Q, U>);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{U\{\}}.
\end{itemdescr}

\indexlibrarymember{get_common_reference}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{AssociatedUnit}@ auto @\libglobal{get_common_reference}@(@\libconcept{AssociatedUnit}@ auto u1,
                                                   @\libconcept{AssociatedUnit}@ auto u2,
                                                   @\libconcept{AssociatedUnit}@ auto... rest)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{get_common_unit(u1, u2, rest...)}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
  get_common_quantity_spec(get_quantity_spec(u1), get_quantity_spec(u2),
                           get_quantity_spec(rest)...);
  { get_common_unit(u1, u2, rest...) } -> AssociatedUnit;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{get_common_reference}{reference}
\begin{itemdecl}
template<@\libconcept{Reference}@ R1, @\libconcept{Reference}@ R2, @\libconcept{Reference}@... Rest>
consteval @\libconcept{Reference}@ auto @\libglobal{get_common_reference}@(R1 r1, R2 r2, Rest... rest)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{reference-t}@<get_common_quantity_spec(get_quantity_spec(R1{}), get_quantity_spec(R2{}),
                                     get_quantity_spec(rest)...),
            get_common_unit(get_unit(R1{}), get_unit(R2{}), get_unit(rest)...)>{};
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
  get_common_quantity_spec(get_quantity_spec(r1), get_quantity_spec(r2),
                           get_quantity_spec(rest)...);
  get_common_unit(get_unit(r1), get_unit(r2), get_unit(rest)...);
}
\end{codeblock}
\end{itemdescr}

\rSec1[qty.rep]{Representation}

\rSec2[qty.rep.general]{General}

\pnum
Subclause \ref{qty.rep} specifies the components
used to constrain the numerical value of a quantity\irefiev{112-01-29}.

\rSec2[qty.rep.traits]{Traits}

\rSec3[qty.fp.traits]{Floating-point}

\begin{itemdecl}
template<typename T>
struct @\exposidnc{actual-value-type}@ : @\exposidnc{cond-value-type}@<T> {}; // see \refcpp{readable.traits}

template<typename T>
  requires(!std::is_pointer_v<T> && !std::is_array_v<T>) &&
          requires { typename std::indirectly_readable_traits<T>::value_type; }
struct @\exposidnc{actual-value-type}@<T> : std::indirectly_readable_traits<T> {};

template<typename T>
using @\exposidnc{actual-value-type-t}@ = @\exposidnc{actual-value-type}@<T>::value_type;

template<typename Rep>
constexpr bool @\libglobal{treat_as_floating_point}@ =
  std::chrono::treat_as_floating_point_v<@\exposidnc{actual-value-type-t}@<Rep>>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\tcode{quantity} and \tcode{quantity_point} use \tcode{treat_as_floating_point}
to help determine whether implicit conversions are allowed among them.

\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize \tcode{treat_as_floating_point}
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.
\end{itemdescr}

\rSec3[qty.char.traits]{Quantity character}

\indexlibraryglobal{disable_scalar}
\indexlibraryglobal{disable_complex}
\indexlibraryglobal{disable_vector}
\begin{itemdecl}
template<typename T>
constexpr bool disable_scalar = false;
template<typename T>
constexpr bool disable_complex = false;
template<typename T>
constexpr bool disable_vector = false;
\end{itemdecl}

\begin{itemdescr}
\pnum
Some quantities are defined as having a numerical value\irefiev{112-01-29} of a specific set\irefiev{102-01-02}.
The representation concepts use these traits
to help determine the sets \tcode{T} represents.

\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize these templates
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.

\pnum
\begin{note}
These templates prevent use of representation types with the library
that satisfy but do not in fact model their corresponding concept.
\end{note}
\end{itemdescr}

\rSec3[qty.val.traits]{Values}

\pnum
\tcode{quantity} and \tcode{quantity_point} use \tcode{representation_values}
to construct special values of its representation type.

\begin{codeblock}
namespace mp_units {

template<typename Rep>
struct @\libglobal{representation_values}@ : std::chrono::duration_values<Rep> {
  static constexpr Rep one() noexcept;
};

}
\end{codeblock}

\pnum
The requirements on \tcode{std::chrono::duration_values<Rep>}\irefcpp{time.traits.duration.values}
also apply to \tcode{representation_values<Rep>}.

\begin{itemdecl}
static constexpr Rep one() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{Rep(1)}.

\pnum
\remarks
The value returned shall be the neutral element for multiplication\irefiev{102-01-19}.
\end{itemdescr}

\rSec2[qty.rep.cpos]{Customization point objects}

\rSec3[qty.rep.cpos.general]{General}

\pnum
Within subclause \ref{qty.rep.cpos},
\term{reified object} is as defined in \refcpp{range.access.general}.

\rSec3[qty.real.cpo]{\tcode{mp_units::real}}

\pnum
The name \tcode{mp_units::real} denotes a customization point object\irefcpp{customization.point.object}.

\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::real(E)} is ill-formed.
\item
If \tcode{auto(t.real())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::real(E)} is expression-equivalent to \tcode{auto(t.real())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(real(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{real} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::real(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::real(E)} is ill-formed.
\end{itemize}

\rSec3[qty.imag.cpo]{\tcode{mp_units::imag}}

\pnum
The name \tcode{mp_units::imag} denotes a customization point object\irefcpp{customization.point.object}.

\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::imag(E)} is ill-formed.
\item
If \tcode{auto(t.imag())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::imag(E)} is expression-equivalent to \tcode{auto(t.imag())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(imag(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{imag} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::imag(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::imag(E)} is ill-formed.
\end{itemize}

\rSec3[qty.modulus.cpo]{\tcode{mp_units::modulus}}

\pnum
The name \tcode{mp_units::modulus} denotes a customization point object\irefcpp{customization.point.object}.

\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::modulus(E)} is ill-formed.
\item
If \tcode{auto(t.modulus())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::modulus(E)} is expression-equivalent to \tcode{auto(t.modulus())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(modulus(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{modulus} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::modulus(E)} is expression-equivalent to that expression.
\item
If \tcode{auto(t.abs())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::modulus(E)} is expres\-sion-equivalent to \tcode{auto(t.abs())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(abs(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{abs} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::modulus(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::modulus(E)} is ill-formed.
\end{itemize}

\rSec3[qty.mag.cpo]{\tcode{mp_units::magnitude}}

\pnum
The name \tcode{mp_units::magnitude} denotes a customization point object\irefcpp{customization.point.object}.

\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::magnitude(E)} is ill-formed.
\item
If \tcode{auto(t.magnitude())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::magnitude(E)} is expression-equivalent to \tcode{auto(t.magnitude())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(magnitude(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{magnitude} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::magnitude(E)} is expression-equivalent to that expression.
\item
Otherwise, if \tcode{auto(t.abs())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::magnitude(\brk{}E)} is expression-equivalent to \tcode{auto(t.abs())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(abs(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{magnitude} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::magnitude(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::magnitude(E)} is ill-formed.
\end{itemize}

\rSec2[qty.rep.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{WeaklyRegular}@ = std::@\stdconcept{copyable}@<T> && std::@\stdconcept{equality_comparable}@<T>;  // \expos

template<typename T>
concept @\defexposconceptnc{Scalar}@ = (!disable_scalar<T>) && @\exposconceptnc{WeaklyRegular}@<T> && requires(T a, T b) {  // \expos
  // scalar operations
  { -a } -> std::common_with<T>;
  { a + b } -> std::common_with<T>;
  { a - b } -> std::common_with<T>;
  { a * b } -> std::common_with<T>;
  { a / b } -> std::common_with<T>;
};
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
using @\exposidnc{value-type-t}@ = @\exposidnc{actual-value-type-t}@<T>;  // \expos, see \ref{qty.fp.traits}

template<typename T>
concept @\defexposconceptnc{Complex}@ =  // \expos
  (!disable_complex<T>) && @\exposconceptnc{WeaklyRegular}@<T> && @\exposconceptnc{Scalar}@<@\exposidnc{value-type-t}@<T>> &&
  std::constructible_from<T, @\exposidnc{value-type-t}@<T>, @\exposidnc{value-type-t}@<T>> &&
  requires(T a, T b, @\exposidnc{value-type-t}@<T> s) {
    // complex operations
    { -a } -> std::common_with<T>;
    { a + b } -> std::common_with<T>;
    { a - b } -> std::common_with<T>;
    { a * b } -> std::common_with<T>;
    { a / b } -> std::common_with<T>;
    { a * s } -> std::common_with<T>;
    { s * a } -> std::common_with<T>;
    { a / s } -> std::common_with<T>;
    ::mp_units::real(a);
    ::mp_units::imag(a);
    ::mp_units::modulus(a);
  };
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{Vector}@ =  // \expos
  (!disable_vector<T>) && @\exposconceptnc{WeaklyRegular}@<T> && @\exposconceptnc{Scalar}@<@\exposidnc{value-type-t}@<T>> &&
  requires(T a, T b, @\exposidnc{value-type-t}@<T> s) {
    // vector operations
    { -a } -> std::common_with<T>;
    { a + b } -> std::common_with<T>;
    { a - b } -> std::common_with<T>;
    { a * s } -> std::common_with<T>;
    { s * a } -> std::common_with<T>;
    { a / s } -> std::common_with<T>;
    ::mp_units::magnitude(a);
  };
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
using @\exposidnc{scaling-factor-type-t}@ =  // \expos
  std::conditional_t<treat_as_floating_point<T>, long double, std::intmax_t>;

template<typename T>
concept @\defexposconceptnc{ScalarRepresentation}@ =  // \expos
  (!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Scalar}@<T> &&
  requires(T a, T b, @\exposidnc{scaling-factor-type-t}@<T> f) {
    // scaling
    { a * f } -> std::common_with<T>;
    { f * a } -> std::common_with<T>;
    { a / f } -> std::common_with<T>;
  };
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{ComplexRepresentation}@ =  // \expos
  (!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Complex}@<T> &&
  requires(T a, T b, @\exposidnc{scaling-factor-type-t}@<T> f) {
    // scaling
    { a * T(f) } -> std::common_with<T>;
    { T(f) * a } -> std::common_with<T>;
    { a / T(f) } -> std::common_with<T>;
  };
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{VectorRepresentation}@ =  // \expos
  (!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Vector}@<T>;
\end{itemdecl}

\pnum
TBD.

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Representation}@ = @\exposconceptnc{ScalarRepresentation}@<T> || @\exposconceptnc{ComplexRepresentation}@<T> ||
                         @\exposconceptnc{VectorRepresentation}@<T>;
\end{itemdecl}

\pnum
A type \tcode{T} models \libconcept{Representation} if
it represents the numerical value of a quantity\irefiev{112-01-29}.

\begin{itemdecl}
template<typename T, quantity_character Ch>
concept @\defexposconceptnc{IsOfCharacter}@ = (Ch == quantity_character::real_scalar && @\exposconceptnc{Scalar}@<T>) ||  // \expos
                        (Ch == quantity_character::complex_scalar && @\exposconceptnc{Complex}@<T>) ||
                        (Ch == quantity_character::vector && @\exposconceptnc{Vector}@<T>);

template<typename T, auto V>
concept @\deflibconcept{RepresentationOf}@ =
  @\libconcept{Representation}@<T> && ((@\libconcept{QuantitySpec}@<decltype(V)> &&
                         (@\exposconceptnc{QuantityKindSpec}@<decltype(V)> || @\exposconceptnc{IsOfCharacter}@<T, V.character>)) ||
                        (std::@\stdconcept{same_as}@<quantity_character, decltype(V)> && @\exposconceptnc{IsOfCharacter}@<T, V>));
\end{itemdecl}

\pnum
A type \tcode{T} models \tcode{\libconcept{RepresentationOf}<V>} if
\tcode{T} models \libconcept{Representation} and
\begin{itemize}
\item
\tcode{V} is a kind of quantity, or
\item
if \tcode{V} is a quantity, then \tcode{T} represents a value of its character, or
\item
if \tcode{V} is a quantity character, then \tcode{T} represents a value of \tcode{V}.
\end{itemize}

\rSec1[qty]{Quantity}

\rSec2[qty.general]{General}

\pnum
Subclause \ref{qty} describes the class template \tcode{quantity}
that represents the value of a quantity\irefiev{112-01-28}
that is an element of a vector space\irefiev{102-03-01,102-03-04}.

\rSec2[qty.like]{Interoperability}

\pnum
The interfaces specified in this subclause and subclause \ref{qty.pt.like}
are used by \tcode{quantity} and \tcode{quantity_point}
to specify conversions with other types representing quantities.
\begin{note}
\ref{qty.chrono} implements them for \tcode{std::chrono::duration} and \tcode{std::chrono::time_point}.
\end{note}

\begin{itemdecl}
template<typename T, template<typename> typename Traits>
concept @\defexposconceptnc{qty-like-impl}@ = requires(const T& qty, const Traits<T>::rep& num) {  // \expos
  { Traits<T>::to_numerical_value(qty) } -> std::@\stdconcept{same_as}@<typename Traits<T>::rep>;
  { Traits<T>::from_numerical_value(num) } -> std::@\stdconcept{same_as}@<T>;
  requires std::same_as<decltype(Traits<T>::explicit_import), const bool>;
  requires std::same_as<decltype(Traits<T>::explicit_export), const bool>;
  typename std::bool_constant<Traits<T>::explicit_import>;
  typename std::bool_constant<Traits<T>::explicit_export>;
};

template<typename T>
concept @\deflibconcept{QuantityLike}@ = !@\libconcept{Quantity}@<T> && @\exposconceptnc{qty-like-impl}@<T, quantity_like_traits> && requires {
  typename quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
};
\end{itemdecl}

\pnum
In the following descriptions, let
\begin{itemize}
\item
\tcode{Traits} be \tcode{quantity_like_traits} or \tcode{quantity_point_like_traits},
\item
\tcode{Q} be a type for which \tcode{Traits<Q>} is specialized,
\item
\tcode{qty} be an lvalue of type \tcode{const Q}, and
\item
\tcode{num} be an lvalue of type \tcode{const Traits<Q>::rep}.
\end{itemize}

\pnum
\tcode{Q} models \tcode{\exposconceptnc{qty-like-impl}<Traits>} if and only if:
\begin{itemize}
\item
\tcode{Traits<Q>::to_numerical_value(qty)} returns the numerical value\irefiev{112-01-29} of \tcode{qty}.
\item
\tcode{Traits<Q>::from_numerical_value(num)} returns a \tcode{Q} with numerical value \tcode{num}.
\item
If \tcode{Traits} is \tcode{quantity_point_like_traits},
both numerical values are offset from \tcode{Traits<Q>::point_origin}.
\end{itemize}

\pnum
If the following expression is \tcode{true}, the specified conversion will be explicit.
\begin{itemize}
\item
\tcode{Traits<Q>::explicit_import} for the conversion from \tcode{Q} to this library's type.
\item
\tcode{Traits<Q>::explicit_export} for the conversion from this library's type to \tcode{Q}.
\end{itemize}

\rSec2[qty.syn]{Class template \tcode{quantity}}

\begin{codeblock}
namespace mp_units {

template<typename T>
concept @\deflibconcept{Quantity}@ = (@\exposidnc{is-derived-from-specialization-of}@<T, quantity>());     // \expos

template<typename Q, auto QS>
concept @\deflibconcept{QuantityOf}@ =                                                       // \expos
  @\libconcept{Quantity}@<Q> && @\libconcept{QuantitySpecOf}@<decltype(auto(Q::quantity_spec)), QS>;

template<@\libconcept{Unit}@ UFrom, @\libconcept{Unit}@ UTo>
consteval bool @\exposidnc{integral-conversion-factor}@(UFrom from, UTo to)              // \expos
{
  return @\exposidnc{is-integral}@(@\exposidnc{get-canonical-unit}@(from).mag / @\exposidnc{get-canonical-unit}@(to).mag);
}

template<typename T>
concept @\defexposconceptnc{IsFloatingPoint}@ = treat_as_floating_point<T>;                      // \expos

template<typename FromRep, typename ToRep, auto FromUnit = one, auto ToUnit = one>
concept @\defexposconceptnc{ValuePreservingTo}@ =                                                // \expos
  @\libconcept{Representation}@<std::remove_cvref_t<FromRep>> && @\libconcept{Representation}@<ToRep> &&
  @\libconcept{Unit}@<decltype(FromUnit)> && @\libconcept{Unit}@<decltype(ToUnit)> && std::@\stdconcept{assignable_from}@<ToRep&, FromRep> &&
  (@\exposidnc{IsFloatingPoint}@<ToRep> || (!@\exposconceptnc{IsFloatingPoint}@<std::remove_cvref_t<FromRep>> &&
                              (@\exposidnc{integral-conversion-factor}@(FromUnit, ToUnit))));

template<typename QFrom, typename QTo>
concept @\defexposconceptnc{QuantityConvertibleTo}@ =                                            // \expos
  @\libconcept{Quantity}@<QFrom> && @\libconcept{Quantity}@<QTo> &&
  @\exposconceptnc{QuantitySpecConvertibleTo}@<QFrom::quantity_spec, QTo::quantity_spec> &&
  @\exposconceptnc{UnitConvertibleTo}@<QFrom::unit, QTo::unit> &&
  @\exposidnc{ValuePreservingTo}@<typename QFrom::rep, typename QTo::rep, QFrom::unit, QTo::unit> &&
  requires(QFrom q) { @\exposidnc{sudo-cast}@<QTo>(q); };                                // see \ref{qty.non.mem.conv}

template<auto QS, typename Func, typename T, typename U>
concept @\defexposconceptnc{InvokeResultOf}@ =                                                   // \expos
  @\libconcept{QuantitySpec}@<decltype(QS)> && std::@\stdconcept{regular_invocable}@<Func, T, U> &&
  @\libconcept{RepresentationOf}@<std::invoke_result_t<Func, T, U>, QS>;

template<typename Func, typename Q1, typename Q2,
         auto QS = std::invoke_result_t<Func, decltype(auto(Q1::quantity_spec)),
                                        decltype(auto(Q2::quantity_spec))>{}>
concept @\defexposconceptnc{InvocableQuantities}@ =                                              // \expos
  @\libconcept{QuantitySpec}@<decltype(QS)> && @\libconcept{Quantity}@<Q1> && @\libconcept{Quantity}@<Q2> &&
  @\exposconceptnc{InvokeResultOf}@<QS, Func, typename Q1::rep, typename Q2::rep>;

template<auto R1, auto R2>
concept @\defexposconceptnc{HaveCommonReference}@ = requires { get_common_reference(R1, R2); };  // \expos

template<typename Func, Quantity Q1, Quantity Q2>
using @\exposidnc{common-quantity-for}@ =                                                // \expos
  quantity<get_common_reference(Q1::reference, Q2::reference),
           std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>;

template<typename Func, typename Q1, typename Q2>
concept @\defexposconceptnc{CommonlyInvocableQuantities}@ =                                      // \expos
  @\libconcept{Quantity}@<Q1> && @\libconcept{Quantity}@<Q2> && @\exposconceptnc{HaveCommonReference}@<Q1::reference, Q2::reference> &&
  std::@\stdconcept{convertible_to}@<Q1, @\exposidnc{common-quantity-for}@<Func, Q1, Q2>> &&
  std::@\stdconcept{convertible_to}@<Q2, @\exposidnc{common-quantity-for}@<Func, Q1, Q2>> &&
  @\exposconceptnc{InvocableQuantities}@<Func, Q1, Q2,
                      get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;

template<auto R1, auto R2, typename Rep1, typename Rep2>
concept @\defexposconceptnc{SameValueAs}@ =                                                      // \expos
  (equivalent(get_unit(R1), get_unit(R2))) && std::@\stdconcept{convertible_to}@<Rep1, Rep2>;

template<typename T>
using @\exposidnc{quantity-like-type}@ =                                                 // \expos
  quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;

template<typename T, typename U, typename TT = std::remove_reference_t<T>>
concept @\defexposconceptnc{Mutable}@ = (!std::is_const_v<TT>) && std::@\stdconcept{derived_from}@<TT, U>;      // \expos

template<@\libconcept{Reference}@ auto R, @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class @\libglobal{quantity}@ {
public:
  Rep @\exposidnc{numerical-value}@;  // \expos

  // member types and values
  static constexpr @\libconcept{Reference}@ auto reference = R;
  static constexpr @\libconcept{QuantitySpec}@ auto quantity_spec = get_quantity_spec(reference);
  static constexpr @\libconcept{Dimension}@ auto dimension = quantity_spec.dimension;
  static constexpr @\libconcept{Unit}@ auto unit = get_unit(reference);
  using rep = Rep;

  // \ref{qty.static}, static member functions
  static constexpr quantity zero() noexcept
    requires @\seebelownc@;
  static constexpr quantity one() noexcept
    requires @\seebelownc@;
  static constexpr quantity min() noexcept
    requires @\seebelownc@;
  static constexpr quantity max() noexcept
    requires @\seebelownc@;

  // \ref{qty.cons}, constructors and assignment

  quantity() = default;
  quantity(const quantity&) = default;
  quantity(quantity&&) = default;
  ~quantity() = default;

  template<typename FwdValue, @\libconcept{Reference}@ R2>
    requires @\exposconceptnc{SameValueAs}@<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
  constexpr quantity(FwdValue&& v, R2);

  template<typename FwdValue, @\libconcept{Reference}@ R2, typename Value = std::remove_cvref_t<FwdValue>>
    requires(!@\exposconceptnc{SameValueAs}@<R2{}, R, Value, Rep>) &&
            @\exposconceptnc{QuantityConvertibleTo}@<quantity<R2{}, Value>, quantity>
  constexpr quantity(FwdValue&& v, R2);

  template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
    requires(unit == ::mp_units::one)
  constexpr quantity(FwdValue&& v);

  template<@\exposconceptnc{QuantityConvertibleTo}@<quantity> Q>
  constexpr explicit(@\seebelownc@) quantity(const Q& q);

  template<@\libconcept{QuantityLike}@ Q>
    requires @\exposconceptnc{QuantityConvertibleTo}@<@\exposidnc{quantity-like-type}@<Q>, quantity>
  constexpr explicit(@\seebelownc@) quantity(const Q& q);

  quantity& operator=(const quantity&) = default;
  quantity& operator=(quantity&&) = default;

  template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
    requires(unit == ::mp_units::one)
  constexpr quantity& operator=(FwdValue&& v);

  // \ref{qty.conv}, conversions

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), Rep>>
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
    requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<reference, ToRep>>
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in() const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
           @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\exposconceptnc{QuantityConvertibleTo}@<quantity,
                                   quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>>
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires requires(const quantity q) { value_cast<ToU{}>(q); }
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
    requires requires(const quantity q) { value_cast<ToRep>(q); }
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in() const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
           @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); }
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;

  // \ref{qty.obs}, numerical value observers

  template<@\libconcept{Unit}@ U>
    requires(equivalent(U{}, unit))
  constexpr rep& numerical_value_ref_in(U) & noexcept;
  template<@\libconcept{Unit}@ U>
    requires(equivalent(U{}, unit))
  constexpr const rep& numerical_value_ref_in(U) const & noexcept;
  template<@\libconcept{Unit}@ U>
    requires(equivalent(U{}, unit))
  void numerical_value_ref_in(U) const && = delete;

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
    requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, U{}), Rep>>
  constexpr rep numerical_value_in(U) const noexcept;

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
    requires requires(const quantity q) { value_cast<U{}>(q); }
  constexpr rep force_numerical_value_in(U) const noexcept;

  // \ref{qty.conv.ops}, conversion operations

  template<typename V_, std::@\stdconcept{constructible_from}@<Rep> Value = std::remove_cvref_t<V_>>
    requires(unit == ::mp_units::one)
  explicit operator V_() const & noexcept;

  template<typename Q_, @\libconcept{QuantityLike}@ Q = std::remove_cvref_t<Q_>>
    requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, @\exposidnc{quantity-like-type}@<Q>>
  constexpr explicit(@\seebelownc@) operator Q_() const noexcept(@\seebelownc@);

  // \ref{qty.unary.ops}, unary operations

  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator+() const
    requires @\seebelownc@;
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator-() const
    requires @\seebelownc@;

  template<@\exposconceptnc{Mutable}@<quantity> Q>
  friend constexpr decltype(auto) operator++(Q&& q)
    requires @\seebelownc@;
  template<@\exposconceptnc{Mutable}@<quantity> Q>
  friend constexpr decltype(auto) operator--(Q&& q)
    requires @\seebelownc@;

  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator++(int)
    requires @\seebelownc@;
  constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator--(int)
    requires @\seebelownc@;

  // \ref{qty.assign.ops}, compound assignment operations

  template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs);
  template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs);
  template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs);

  template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs);
  template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs);

  template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs);
  template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs);

  // \ref{qty.arith.ops}, arithmetic operations

  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::plus<>, quantity, quantity<R2, Rep2>>
  friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::minus<>, quantity, quantity<R2, Rep2>>
  friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) &&
            @\exposconceptnc{CommonlyInvocableQuantities}@<std::modulus<>, quantity, quantity<R2, Rep2>>
  friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs);

  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const Value& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const Value& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const Value& rhs);

  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator+(const Value& lhs, const Q& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator-(const Value& lhs, const Q& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires(Q::unit == ::mp_units::one) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
  friend constexpr @\libconcept{Quantity}@ auto operator%(const Value& lhs, const Q& rhs);

  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\exposconceptnc{InvocableQuantities}@<std::multiplies<>, quantity, quantity<R2, Rep2>>
  friend constexpr @\libconcept{Quantity}@ auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\exposconceptnc{InvocableQuantities}@<std::divides<>, quantity, quantity<R2, Rep2>>
  friend constexpr @\libconcept{Quantity}@ auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs);

  template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
    requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, Rep, const Value&>
  friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Q& lhs, const Value& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
    requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, Rep, const Value&>
  friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator/(const Q& lhs, const Value& rhs);

  template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
    requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, const Value&, Rep>
  friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Value& lhs, const Q& rhs);
  template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
    requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
            @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, const Value&, Rep>
  friend constexpr @\libconcept{Quantity}@ auto operator/(const Value&, const Q&);

  // \ref{qty.cmp}, comparison

  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs);

  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires @\seebelownc@
  friend constexpr bool operator==(const Q& lhs, const Value& rhs);
  template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
    requires @\seebelownc@
  friend constexpr auto operator<=>(const Q& lhs, const Value& rhs);

  // \ref{qty.val.cmp}, value comparison
  friend constexpr bool is_eq_zero(const quantity& q) requires @\seebelownc@;
  friend constexpr bool is_neq_zero(const quantity& q) requires @\seebelownc@;
  friend constexpr bool is_lt_zero(const quantity& q) requires @\seebelownc@;
  friend constexpr bool is_gt_zero(const quantity& q) requires @\seebelownc@;
  friend constexpr bool is_lteq_zero(const quantity& q) requires @\seebelownc@;
  friend constexpr bool is_gteq_zero(const quantity& q) requires @\seebelownc@;
};

template<@\libconcept{Representation}@ Value, @\libconcept{Reference}@ R>
quantity(Value, R) -> quantity<R{}, Value>;

template<@\libconcept{Representation}@ Value>
quantity(Value) -> quantity<one, Value>;

template<@\libconcept{QuantityLike}@ Q>
explicit(quantity_like_traits<Q>::explicit_import) quantity(Q)
  -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;

}
\end{codeblock}

\pnum
\tcode{quantity<R, Rep>} is a structural type\irefcppx{temp.param}{term.structural.type}
if \tcode{Rep} is a structural type.

\rSec2[qty.static]{Static member functions}

\indexlibrarymember{zero}{quantity}
\indexlibrarymember{one}{quantity}
\indexlibrarymember{min}{quantity}
\indexlibrarymember{max}{quantity}
\begin{itemdecl}
static constexpr quantity zero() noexcept
  requires @\seebelownc@;
static constexpr quantity one() noexcept
  requires @\seebelownc@;
static constexpr quantity min() noexcept
  requires @\seebelownc@;
static constexpr quantity max() noexcept
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \placeholder{F} be one of \tcode{zero}, \tcode{one}, \tcode{min}, and \tcode{max}.

\pnum
\returns
\tcode{\{representation_values<rep>::\placeholdernc{F}(), R\}}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { representation_values<rep>::@\placeholdernc{F}@(); }
\end{codeblock}
\end{itemdescr}

\rSec2[qty.cons]{Constructors and assignment}

\indexlibraryctor{quantity}
\begin{itemdecl}
template<typename FwdValue, @\libconcept{Reference}@ R2>
  requires @\exposconceptnc{SameValueAs}@<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2);

template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
  requires(unit == ::mp_units::one)
constexpr quantity(FwdValue&& v);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposidnc{numerical-value} with \tcode{std::forward<FwdValue>(v)}.
\end{itemdescr}

\indexlibraryctor{quantity}
\begin{itemdecl}
template<typename FwdValue, @\libconcept{Reference}@ R2, typename Value = std::remove_cvref_t<FwdValue>>
  requires(!@\exposconceptnc{SameValueAs}@<R2{}, R, Value, Rep>) &&
          @\exposconceptnc{QuantityConvertibleTo}@<quantity<R2{}, Value>, quantity>
constexpr quantity(FwdValue&& v, R2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{quantity(quantity<R2\{\}, Value>\{std::forward<FwdValue>(v), R2\{\}\})}.
\end{itemdescr}

\indexlibraryctor{quantity}
\begin{itemdecl}
template<@\exposconceptnc{QuantityConvertibleTo}@<quantity> Q>
constexpr explicit(!std::@\stdconcept{convertible_to}@<typename Q::rep, Rep>) quantity(const Q& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposidnc{sudo-cast}<quantity>(q)}\iref{qty.non.mem.conv}.
\end{itemdescr}

\indexlibraryctor{quantity}
\begin{itemdecl}
template<@\libconcept{QuantityLike}@ Q>
  requires @\exposconceptnc{QuantityConvertibleTo}@<@\exposidnc{quantity-like-type}@<Q>, quantity>
constexpr explicit(@\seebelownc@) quantity(const Q& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q),
                              quantity_like_traits<Q>::reference})
\end{codeblock}

\pnum
\remarks
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
quantity_like_traits<Q>::explicit_import ||
  !std::@\stdconcept{convertible_to}@<typename quantity_like_traits<Q>::rep, Rep>
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
  requires(unit == ::mp_units::one)
constexpr quantity& operator=(FwdValue&& v);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposidnc{numerical-value} = std::forward<FwdValue>(v)}.

\pnum
\returns
\tcode{*this}.
\end{itemdescr}

\rSec2[qty.conv]{Conversions}

\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), Rep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity<\exposidnc{make-reference}(quantity_spec, ToU\{\}), Rep>\{*this\};}
\end{itemdescr}

\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
  requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<reference, ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in() const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity<reference, ToRep>\{*this\};}
\end{itemdescr}

\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
         @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\exposconceptnc{QuantityConvertibleTo}@<quantity,
                                 quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>{*this};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires requires(const quantity q) { value_cast<ToU{}>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToU\{\}>(*this);}
\end{itemdescr}

\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
  requires requires(const quantity q) { value_cast<ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in() const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToRep>(*this);}
\end{itemdescr}

\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
         @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToU\{\}, ToRep>(*this);}
\end{itemdescr}

\rSec2[qty.obs]{Numerical value observers}

\indexlibrarymember{numerical_value_ref_in}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ U>
  requires(equivalent(U{}, unit))
constexpr rep& numerical_value_ref_in(U) & noexcept;
template<@\libconcept{Unit}@ U>
  requires(equivalent(U{}, unit))
constexpr const rep& numerical_value_ref_in(U) const & noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\exposidnc{numerical-value}.
\end{itemdescr}

\indexlibrarymember{numerical_value_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
  requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, U{}), Rep>>
constexpr rep numerical_value_in(U) const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return (*this).in(U\{\}).\exposidnc{numerical-value};}
\end{itemdescr}

\indexlibrarymember{force_numerical_value_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
  requires requires(const quantity q) { value_cast<U{}>(q); }
constexpr rep force_numerical_value_in(U) const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return (*this).force_in(U\{\}).\exposidnc{numerical-value};}
\end{itemdescr}

\rSec2[qty.conv.ops]{Conversion operations}

\indexlibrarymisc{\idxcode{quantity}}{\idxcode{operator constructible_from<Rep>}}
\begin{itemdecl}
template<typename V_, std::@\stdconcept{constructible_from}@<Rep> Value = std::remove_cvref_t<V_>>
  requires(unit == ::mp_units::one)
explicit operator V_() const & noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\exposidnc{numerical-value}.
\end{itemdescr}

\indexlibrarymisc{\idxcode{quantity}}{\idxcode{operator QuantityLike}}
\begin{itemdecl}
template<typename Q_, @\libconcept{QuantityLike}@ Q = std::remove_cvref_t<Q_>>
  requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, @\exposidnc{quantity-like-type}@<Q>>
constexpr explicit(@\seebelownc@) operator Q_() const noexcept(@\seebelownc@);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_like_traits<Q>::from_numerical_value(
  numerical_value_in(get_unit(quantity_like_traits<Q>::reference)));
\end{codeblock}

\pnum
\remarks
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
quantity_like_traits<Q>::explicit_export ||
  !std::@\stdconcept{convertible_to}@<Rep, typename quantity_like_traits<Q>::rep>
\end{codeblock}
The exception specification is equivalent to:
\begin{codeblock}
noexcept(quantity_like_traits<Q>::from_numerical_value(@\exposidnc{numerical-value}@)) &&
  std::is_nothrow_copy_constructible_v<rep>
\end{codeblock}
\end{itemdescr}

\rSec2[qty.unary.ops]{Unary operations}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\begin{itemdecl}
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator+() const
  requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator-() const
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{@\exposidnc{numerical-value}, reference\};}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(const rep v) {
  { @\atsign@v } -> std::@\stdconcept{common_with}@<rep>;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator++}{quantity}
\indexlibrarymember{operator--}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator++(Q&& q)
  requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator--(Q&& q)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{@q.\exposidnc{numerical-value}}.

\pnum
\returns
\tcode{std::forward<Q>(q)}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(rep& v) {
  { @\atsign@v } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator++}{quantity}
\indexlibrarymember{operator--}{quantity}
\begin{itemdecl}
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator++(int)
  requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator--(int)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{\exposid{numerical-value}@, reference\};}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(rep& v) {
  { v@\atsign@ } -> std::@\stdconcept{common_with}@<rep>;
}
\end{codeblock}
\end{itemdescr}

\rSec2[qty.assign.ops]{Compound assignment operations}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator+=}{quantity}
\indexlibrarymember{operator-=}{quantity}
\indexlibrarymember{operator\%=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{\%=}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.

\pnum
\effects
Equivalent to
\tcode{lhs.\exposid{numerical-value} @ rhs.in(lhs.unit).\exposid{numerical-value}}.

\pnum
\returns
\tcode{std::forward<Q>(lhs)}.

\pnum
\remarks
Let \placeholder{C} be
\begin{itemize}
\item
\tcode{(!treat_as_floating_point<rep>)} if \tcode{@} is \tcode{\%=}, and
\item
\tcode{true} otherwise.
\end{itemize}
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2, Rep2>, quantity> && @\placeholder{C}@ &&
requires(rep& a, const Rep2 b) {
  { a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}

\pnum
\recommended
If \tcode{equivalent(unit, get_unit(rhs.reference))} is \tcode{true},
then the expression \tcode{rhs.in(lhs.unit)} is replaced with \tcode{rhs}.
\end{itemdescr}

\indexlibrarymember{operator*=}{quantity}
\indexlibrarymember{operator/=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
  requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
  requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/=}, then \tcode{rhs != representation_values<Value>::zero()} is \tcode{true}.

\pnum
\effects
Equivalent to
\tcode{lhs.\exposid{numerical-value} @ rhs}.

\pnum
\returns
\tcode{std::forward<Q>(lhs)}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(!@\libconcept{Quantity}@<Value>) && requires(rep& a, const Value b) {
  { a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator*=}{quantity}
\indexlibrarymember{operator/=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return std::forward<Q>(lhs) @ rhs.\exposid{numerical-value};}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Q2::unit == ::mp_units::one) && @\exposconceptnc{ValuePreservingTo}@<typename Q2::rep, Rep> &&
requires(rep& a, const Q2::rep b) {
  { a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\end{itemdescr}

\rSec2[qty.arith.ops]{Arithmetic operations}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::plus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::minus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) &&
          @\exposconceptnc{CommonlyInvocableQuantities}@<std::modulus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \placeholder{F} be the first argument to \exposconceptnc{CommonlyInvocableQuantities}.

\pnum
\expects
If \tcode{@} is \tcode{\%}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
using ret = @\exposidnc{common-quantity-for}@<@\placeholdernc{F}@, quantity, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return ::mp_units::quantity{
  ret_lhs.numerical_value_ref_in(ret::unit) @\atsign@ ret_rhs.numerical_value_ref_in(ret::unit),
  ret::reference};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const Value& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return lhs @ ::mp_units::quantity\{rhs\};}
\end{itemdescr}

\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires(Q::unit == ::mp_units::one) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Value& lhs, const Q& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{lhs\} @ rhs;}
\end{itemdescr}

\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\exposconceptnc{InvocableQuantities}@<std::multiplies<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\exposconceptnc{InvocableQuantities}@<std::divides<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{
  lhs.numerical_value_ref_in(unit) @\atsign@ rhs.numerical_value_ref_in(rhs.unit), R @\atsign@ R2};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
  requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
  requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator/(const Q& lhs, const Value& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{rhs != representation_values<Value>::zero()} is \tcode{true}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{lhs.numerical_value_ref_in(unit) @\atsign@ rhs, R};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
  requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, const Value&, Rep>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Value& lhs, const Q& rhs);
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
  requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
          @\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, const Value&, Rep>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Value& lhs, const Q& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{lhs @\atsign@ rhs.numerical_value_ref_in(unit), ::mp_units::one @\atsign@ R};
\end{codeblock}
\end{itemdescr}

\rSec2[qty.cmp]{Comparison}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator==}{quantity}
\indexlibrarymember{operator<=>}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable}} if \tcode{@} is \tcode{<=>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
using ct = std::common_type_t<quantity, quantity<R2, Rep2>>;
const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) @\atsign@ ct_rhs.numerical_value_ref_in(ct::unit);
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
  typename std::common_type_t<quantity, quantity<R2, Rep2>>;
} && @\placeholder{C}@<typename std::common_type_t<quantity, quantity<R2, Rep2>>::rep>
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator==}{quantity}
\indexlibrarymember{operator<=>}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
  requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const Value& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable_with}} if \tcode{@} is \tcode{<=>}.

\pnum
\returns
\tcode{lhs.numerical_value_ref_in(unit) @ rhs}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Q::unit == ::mp_units::one) && @\placeholder{C}@<Rep, Value>
\end{codeblock}
\end{itemdescr}

\rSec2[qty.val.cmp]{Value comparison}

\indexlibrarymember{is_eq_zero}{quantity}
\indexlibrarymember{is_neq_zero}{quantity}
\indexlibrarymember{is_lt_zero}{quantity}
\indexlibrarymember{is_gt_zero}{quantity}
\indexlibrarymember{is_lteq_zero}{quantity}
\indexlibrarymember{is_gteq_zero}{quantity}
\begin{itemdecl}
friend constexpr bool is_eq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_neq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lteq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gteq_zero(const quantity& q) requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{is_\placeholdernc{F}_zero} be the function name.

\pnum
\returns
\begin{itemize}
\item
If \tcode{\placeholdernc{F}} is \tcode{eq}, returns \tcode{q == zero()}.
\item
Otherwise, if \tcode{\placeholdernc{F}} is \tcode{neq}, returns \tcode{q != zero()}.
\item
Otherwise, returns \tcode{is_\placeholdernc{F}(q <=> zero())}\irefcpp{compare.syn}.
\end{itemize}

\pnum
\remarks
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \placeholder{F} is \tcode{eq} or \tcode{neq}, and
\tcode{std::\stdconcept{three_way_comparable_with}} otherwise.
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
  { T::zero() } -> @\placeholder{C}@<quantity>;
}
\end{codeblock}
\end{itemdescr}

\rSec2[qty.delta]{Construction helper \tcode{delta}}

\indexlibraryglobal{delta_}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{Reference}@ R>
struct delta_ {
  template<typename FwdRep,
           @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const;
};

}
\end{codeblock}

\indexlibrarymember{operator()}{delta_}
\begin{itemdecl}
template<typename FwdRep,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), R\{\}\};}
\end{itemdescr}

\rSec2[qty.non.mem.conv]{Non-member conversions}

\indexlibrarymemberexpos{quantity}{sudo-cast}
\begin{itemdecl}
template<@\libconcept{Quantity}@ To, typename FwdFrom, @\libconcept{Quantity}@ From = std::remove_cvref_t<FwdFrom>>
  requires @\seebelownc@
constexpr To @\exposidnc{sudo-cast}@(FwdFrom&& q);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}

\pnum
\tcode{value_cast} is an explicit cast that allows truncation.

\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires(convertible(Q::reference, ToU))
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<@\exposidnc{make-reference}@(Q::quantity_spec, ToU), typename Q::rep>>(
  std::forward<FwdQ>(q));
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Representation}@ ToRep, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires @\libconcept{RepresentationOf}@<ToRep, Q::quantity_spec> &&
           std::@\stdconcept{constructible_from}@<ToRep, typename Q::rep>
constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<Q::reference, ToRep>>(std::forward<FwdQ>(q));
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, typename FwdQ,
         @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, typename FwdQ,
         @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<@\exposidnc{make-reference}@(Q::quantity_spec, ToU), ToRep>>(
  std::forward<FwdQ>(q));
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(Q::reference, ToU)) && @\libconcept{RepresentationOf}@<ToRep, Q::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename Q::rep>
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Quantity}@ ToQ, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires(convertible(Q::reference, ToQ::unit)) && (ToQ::quantity_spec == Q::quantity_spec) &&
          std::@\stdconcept{constructible_from}@<typename ToQ::rep, typename Q::rep>
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposidnc{sudo-cast}<ToQ>(std::forward<FwdQ>(q));}
\end{itemdescr}

\pnum
\tcode{quantity_cast} is an explicit cast that allows converting to more specific quantities.
\begin{example}
\begin{codeblock}
auto length = isq::length(42 * m);
auto distance = quantity_cast<isq::distance>(length);
\end{codeblock}
\end{example}

\indexlibrarymember{quantity_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto ToQS, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
  requires @\exposconceptnc{QuantitySpecCastableTo}@<Q::quantity_spec, ToQS>
constexpr @\libconcept{Quantity}@ auto quantity_cast(FwdQ&& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, @\exposidnc{make-reference}@(ToQS, Q::unit)};
\end{codeblock}
\end{itemdescr}

\rSec2[qty.common.type]{\tcode{std::common_type} specializations}

\begin{codeblock}
template<mp_units::@\libconcept{Quantity}@ Q1, mp_units::@\libconcept{Quantity}@ Q2>
  requires requires {
    { mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference;
    typename std::common_type_t<typename Q1::rep, typename Q2::rep>;
    requires mp_units::@\libconcept{RepresentationOf}@<std::common_type_t<typename Q1::rep, typename Q2::rep>,
                                        mp_units::get_common_quantity_spec(Q1::quantity_spec,
                                                                           Q2::quantity_spec)>;
  }
struct @\libspec{std::common_type}{quantity}@<Q1, Q2> {
  using type = mp_units::quantity<mp_units::get_common_reference(Q1::reference, Q2::reference),
                                  std::common_type_t<typename Q1::rep, typename Q2::rep>>;
};

template<mp_units::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
  requires(Q::unit == mp_units::one) && requires {
    typename mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
  }
struct @\libspec{std::common_type}{quantity}@<Q, Value> {
  using type = mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
};
\end{codeblock}

\rSec1[qty.pt]{Quantity point}

\rSec2[qty.pt.general]{General}

\pnum
Subclause \ref{qty.pt} describes the class template \tcode{quantity_point}
that represents the value of a quantity\irefiev{112-01-28}
that is an element of an affine space\irefiev{102-03-02,102-04-01}.

\rSec2[qty.pt.orig]{Point origin}

\rSec3[qty.pt.orig.general]{General}

\pnum
This subclause specifies the components
for defining the origin of an affine space.
An \defn{origin} is a point from which measurements\irefiev{112-04-01} take place.

\rSec3[qty.pt.orig.concepts]{Concepts}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{PointOrigin}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{point-origin-interface}@>;

template<typename T, auto QS>
concept @\deflibconcept{PointOriginFor}@ = @\libconcept{PointOrigin}@<T> && @\libconcept{QuantitySpecOf}@<decltype(QS), T::@\exposidnc{quantity-spec}@>;

template<typename T, auto V>
concept @\defexposconceptnc{SameAbsolutePointOriginAs}@ =  // \expos
  @\libconcept{PointOrigin}@<T> && @\libconcept{PointOrigin}@<decltype(V)> && @\exposidnc{same-absolute-point-origins}@(T{}, V);
\end{itemdecl}

\rSec3[qty.pt.orig.types]{Types}

\rSec4[qty.abs.pt.orig]{Absolute}

\begin{codeblock}
namespace mp_units {

template<@\libconcept{QuantitySpec}@ auto QS>
struct @\libglobal{absolute_point_origin}@ : @\exposidnc{point-origin-interface}@ {
  static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = QS;  // \expos
};

}
\end{codeblock}

\pnum
An \defnadj{absolute}{origin} is an origin
chosen by convention and not defined in terms of another origin.
A specialization of \tcode{absolute_point_origin} is used as a base type when defining an absolute origin.
\tcode{QS} is the quantity the origin represents.

\rSec4[qty.rel.pt.orig]{Relative}

\begin{codeblock}
namespace mp_units {

template<@\libconcept{QuantityPoint}@ auto QP>
struct @\libglobal{relative_point_origin}@ : @\exposidnc{point-origin-interface}@ {
  static constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{quantity-point}@ = QP;       // \expos
  static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = @\seebelownc@;  // \expos
  static constexpr @\libconcept{PointOrigin}@ auto @\exposidnc{absolute-point-origin}@ =      // \expos
    QP.absolute_point_origin;
};

}
\end{codeblock}

\pnum
A \defnadj{relative}{origin} is an origin
of a subspace\irefiev{102-03-03}.
A specialization of \tcode{relative_point_origin} is used as a base type when defining a relative origin \placeholder{O}.
\placeholder{O} is offset from \tcode{QP.absolute_point_origin} by \tcode{QP.quantity_from_zero()}.

\pnum
The member \exposid{quantity-spec} is equal to
\tcode{QP.point_origin.\exposidnc{quantity-spec}} if
\begin{codeblock}
@\exposconceptnc{QuantityKindSpec}@<decltype(auto(QP.@\exposidnc{quantity-spec}@))>
\end{codeblock}
is satisfied, and
to \tcode{QP.\exposidnc{quantity-spec}} otherwise.

\rSec4[qty.zeroth.pt.orig]{Zeroth}

\begin{codeblock}
namespace mp_units {

template<@\libconcept{QuantitySpec}@ auto QS>
struct @\libglobal{zeroth_point_origin_}@ final : absolute_point_origin<QS> {};

}
\end{codeblock}

\pnum
\tcode{zeroth_point_origin_<QS>} represents an origin
chosen by convention as the value $0$ of the quantity \tcode{QS}.

\rSec3[qty.pt.orig.ops]{Operations}

\begin{codeblock}
namespace mp_units {

struct @\exposidnc{point-origin-interface}@ {
  template<@\libconcept{PointOrigin}@ PO, typename FwdQ,
           @\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
  friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, FwdQ&& q);
  template<@\libconcept{Quantity}@ FwdQ, @\libconcept{PointOrigin}@ PO,
           @\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
  friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(FwdQ&& q, PO);

  template<@\libconcept{PointOrigin}@ PO, @\libconcept{Quantity}@ Q>
    requires @\libconcept{ReferenceOf}@<decltype(auto(Q::reference)), PO::@\exposidnc{quantity-spec}@>
  friend constexpr @\libconcept{QuantityPoint}@ auto operator-(PO po, const Q& q)
    requires requires { -q; };

  template<@\libconcept{PointOrigin}@ PO1, @\exposconceptnc{SameAbsolutePointOriginAs}@<PO1{}> PO2>
    requires @\seebelownc@
  friend constexpr @\libconcept{Quantity}@ auto operator-(PO1 po1, PO2 po2);

  template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
  friend consteval bool operator==(PO1 po1, PO2 po2);
};

}
\end{codeblock}

\indexlibrarymemberexpos{operator+}{point-origin-interface}
\indexlibrarymemberexpos{operator+}{quantity}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO, typename FwdQ,
         @\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, FwdQ&& q);
template<@\libconcept{Quantity}@ FwdQ, @\libconcept{PointOrigin}@ PO,
         @\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(FwdQ&& q, PO);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity_point\{std::forward<FwdQ>(q), PO\{\}\};}
\end{itemdescr}

\indexlibrarymemberexpos{operator-}{point-origin-interface}
\indexlibrarymemberexpos{operator-}{quantity}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO, @\libconcept{Quantity}@ Q>
  requires @\libconcept{ReferenceOf}@<decltype(auto(Q::reference)), PO::@\exposidnc{quantity-spec}@>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(PO po, const Q& q)
  requires requires { -q; };
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return po + -q;}
\end{itemdescr}

\indexlibrarymemberexpos{operator-}{point-origin-interface}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\exposconceptnc{SameAbsolutePointOriginAs}@<PO1{}> PO2>
  requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO1 po1, PO2 po2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>()) {
  return po1 - po2.@\exposidnc{quantity-point}@;
} else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>()) {
  return po1.@\exposidnc{quantity-point}@ - po2;
} else {
  return po1.@\exposidnc{quantity-point}@ - po2.@\exposidnc{quantity-point}@;
}
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{QuantitySpecOf}@<decltype(auto(PO1::@\exposidnc{quantity-spec}@)), PO2::@\exposidnc{quantity-spec}@> &&
  (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() ||
   @\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
\end{codeblock}
\end{itemdescr}

\indexlibrarymemberexpos{operator==}{point-origin-interface}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
friend consteval bool operator==(PO1 po1, PO2 po2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>() &&
              @\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>())
  return std::is_same_v<PO1, PO2> ||
         (@\exposidnc{is-specialization-of}@<PO1, zeroth_point_origin>() &&
          @\exposidnc{is-specialization-of}@<PO2, zeroth_point_origin>() &&
          interconvertible(po1.@\exposidnc{quantity-spec}@, po2.@\exposidnc{quantity-spec}@));
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() &&
                   @\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
  return PO1::@\exposidnc{quantity-point}@ == PO2::@\exposidnc{quantity-point}@;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>())
  return @\exposidnc{same-absolute-point-origins}@(po1, po2) &&
         is_eq_zero(PO1::@\exposidnc{quantity-point}@.quantity_from_zero());
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
  return @\exposidnc{same-absolute-point-origins}@(po1, po2) &&
         is_eq_zero(PO2::@\exposidnc{quantity-point}@.quantity_from_zero());
\end{codeblock}
\end{itemdescr}

\rSec3[qty.pt.orig.utils]{Utilities}

\rSec4[qty.same.abs.pt.origs]{Same absolute}

\indexlibrarymemberexpos{PointOrigin}{same-absolute-point-origins}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
consteval bool @\exposidnc{same-absolute-point-origins}@(PO1 po1, PO2 po2);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>() &&
              @\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>())
  return po1 == po2;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() &&
                   @\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
  return po1.@\exposidnc{absolute-point-origin}@ == po2.@\exposidnc{absolute-point-origin}@;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>())
  return po1.@\exposidnc{absolute-point-origin}@ == po2;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
  return po1 == po2.@\exposidnc{absolute-point-origin}@;
else
  return false;
\end{codeblock}
\end{itemdescr}

\rSec4[qty.def.pt.orig]{Default}

\indexlibrarymember{Reference}{default_point_origin}
\begin{itemdecl}
template<@\libconcept{Reference}@ R>
consteval @\libconcept{PointOriginFor}@<get_quantity_spec(R{})> auto default_point_origin(R);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { get_unit(R{}).@\exposidnc{point-origin}@; })
  return get_unit(R{}).@\exposidnc{point-origin}@;
else
  return zeroth_point_origin<get_quantity_spec(R{})>;
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.like]{Interoperability}

\begin{itemdecl}
template<typename T>
concept @\deflibconcept{QuantityPointLike}@ =
  !@\libconcept{QuantityPoint}@<T> &&
  @\exposconceptnc{qty-like-impl}@<T, quantity_point_like_traits> &&  // see \ref{qty.like}
  requires {
    typename quantity_point<quantity_point_like_traits<T>::reference,
                            quantity_point_like_traits<T>::point_origin,
                            typename quantity_point_like_traits<T>::rep>;
  };
\end{itemdecl}

\rSec2[qty.pt.syn]{Class template \tcode{quantity_point}}

\begin{codeblock}
namespace mp_units {

template<typename T>
concept @\deflibconcept{QuantityPoint}@ = (@\exposidnc{is-derived-from-specialization-of}@<T, quantity_point>());

template<typename QP, auto V>
concept @\deflibconcept{QuantityPointOf}@ =
  @\libconcept{QuantityPoint}@<QP> && (@\libconcept{QuantitySpecOf}@<decltype(auto(QP::quantity_spec)), V> ||
                        @\exposconceptnc{SameAbsolutePointOriginAs}@<decltype(auto(QP::absolute_point_origin)), V>);

template<@\libconcept{Reference}@ auto R,
         @\libconcept{PointOriginFor}@<get_quantity_spec(R)> auto PO = default_point_origin(R),
         @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class @\libglobal{quantity_point}@ {
public:
  // member types and values
  static constexpr @\libconcept{Reference}@ auto reference = R;
  static constexpr @\libconcept{QuantitySpec}@ auto quantity_spec = get_quantity_spec(reference);
  static constexpr @\libconcept{Dimension}@ auto dimension = quantity_spec.dimension;
  static constexpr @\libconcept{Unit}@ auto unit = get_unit(reference);
  static constexpr @\libconcept{PointOrigin}@ auto absolute_point_origin = @\seebelownc@;
  static constexpr @\libconcept{PointOrigin}@ auto point_origin = PO;
  using rep = Rep;
  using quantity_type = quantity<reference, Rep>;

  quantity_type @\exposidnc{quantity-from-origin}@;  // \expos

  // \ref{qty.pt.static}, static member functions
  static constexpr quantity_point min() noexcept
    requires @\seebelownc@;
  static constexpr quantity_point max() noexcept
    requires @\seebelownc@;

  // \ref{qty.pt.cons}, constructors and assignment

  quantity_point() = default;
  quantity_point(const quantity_point&) = default;
  quantity_point(quantity_point&&) = default;
  ~quantity_point() = default;

  template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
    requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> &&
             (point_origin == default_point_origin(R)) &&
             (implicitly_convertible(Q::quantity_spec, quantity_spec))
  constexpr explicit quantity_point(FwdQ&& q);

  template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
    requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ>
  constexpr quantity_point(FwdQ&& q, decltype(PO));

  template<typename FwdQ, @\libconcept{PointOrigin}@ PO2,
           @\libconcept{QuantityOf}@<PO2::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
    requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> && @\exposconceptnc{SameAbsolutePointOriginAs}@<PO2, PO>
  constexpr quantity_point(FwdQ&& q, PO2);

  template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
    requires std::@\stdconcept{constructible_from}@<quantity_type, typename QP::quantity_type>
  constexpr explicit(!std::@\stdconcept{convertible_to}@<typename QP::quantity_type, quantity_type>)
    quantity_point(const QP& qp);

  template<@\libconcept{QuantityPointLike}@ QP>
    requires @\seebelownc@
  constexpr explicit(@\seebelownc@) quantity_point(const QP& qp);

  quantity_point& operator=(const quantity_point&) = default;
  quantity_point& operator=(quantity_point&&) = default;

  // \ref{qty.pt.conv}, conversions

  template<@\exposconceptnc{SameAbsolutePointOriginAs}@<absolute_point_origin> NewPO>
  constexpr @\libconcept{QuantityPointOf}@<(NewPO{})> auto point_for(NewPO new_origin) const;

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in() const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
           @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;

  template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in() const;

  template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
           @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
    requires @\seebelownc@
  constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;

  // \ref{qty.pt.obs}, quantity value observers

  template<@\libconcept{PointOrigin}@ PO2>
    requires(PO2{} == point_origin)
  constexpr quantity_type& quantity_ref_from(PO2) & noexcept;
  template<@\libconcept{PointOrigin}@ PO2>
    requires(PO2{} == point_origin)
  constexpr const quantity_type& quantity_ref_from(PO2) const & noexcept;
  template<@\libconcept{PointOrigin}@ PO2>
    requires(PO2{} == point_origin)
  void quantity_ref_from(PO2) const && = delete;

  template<@\libconcept{PointOrigin}@ PO2>
    requires requires(const quantity_point qp) { qp - PO2{}; }
  constexpr @\libconcept{Quantity}@ auto quantity_from(PO2) const;

  template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
  constexpr @\libconcept{Quantity}@ auto quantity_from(const QP&) const;

  constexpr @\libconcept{Quantity}@ auto quantity_from_zero() const;

  // \ref{qty.pt.conv.ops}, conversion operations
  template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
    requires @\seebelownc@
  constexpr explicit(@\seebelownc@) operator QP_() const & noexcept(@\seebelownc@);
  template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
    requires @\seebelownc@
  constexpr explicit(@\seebelownc@) operator QP_() && noexcept(@\seebelownc@);

  // \ref{qty.pt.unary.ops}, unary operations

  template<@\exposconceptnc{Mutable}@<quantity_point> QP>
  friend constexpr decltype(auto) operator++(QP&& qp)
    requires @\seebelownc@;
  template<@\exposconceptnc{Mutable}@<quantity_point> QP>
  friend constexpr decltype(auto) operator--(QP&& qp)
    requires @\seebelownc@;

  constexpr quantity_point operator++(int)
    requires @\seebelownc@;
  constexpr quantity_point operator--(int)
    requires @\seebelownc@;

  // \ref{qty.pt.assign.ops}, compound assignment operations
  template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q);
  template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
    requires @\seebelownc@
  friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q);

  // \ref{qty.pt.arith.ops}, arithmetic operations

  template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
  friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
    requires @\seebelownc@;
  template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
  friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const quantity<R2, Rep2>& q, const QP& qp)
    requires @\seebelownc@;
  template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
  friend constexpr @\libconcept{QuantityPoint}@ auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
    requires @\seebelownc@;

  template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
  friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& lhs, const QP2& rhs)
    requires @\seebelownc@;

  template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
    requires @\seebelownc@
  friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& qp, PO2 po);
  template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
    requires @\seebelownc@
  friend constexpr @\libconcept{Quantity}@ auto operator-(PO2 po, const QP& qp);

  // \ref{qty.pt.cmp}, comparison
  template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
    requires @\seebelownc@
  friend constexpr bool operator==(const QP& lhs, const QP2& rhs);
  template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
    requires @\seebelownc@
  friend constexpr auto operator<=>(const QP& lhs, const QP2& rhs);
};

template<@\libconcept{Quantity}@ Q>
explicit quantity_point(Q q)
  -> quantity_point<Q::reference, default_point_origin(Q::reference), typename Q::rep>;

template<@\libconcept{Quantity}@ Q, @\libconcept{PointOriginFor}@<Q::quantity_spec> PO>
quantity_point(Q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;

template<@\libconcept{QuantityPointLike}@ QP, typename Traits = quantity_point_like_traits<QP>>
explicit(quantity_point_like_traits<QP>::explicit_import) quantity_point(QP)
  -> quantity_point<Traits::reference, Traits::point_origin, typename Traits::rep>;

}
\end{codeblock}

\pnum
\tcode{quantity_point<R, PO, Rep>} is a structural type\irefcppx{temp.param}{term.structural.type}
if \tcode{Rep} is a structural type.

\pnum
The member \tcode{absolute_point_origin} is equal to \tcode{PO} if
\begin{codeblock}
@\exposidnc{is-derived-from-specialization-of}@<decltype(PO), absolute_point_origin>()
\end{codeblock}
is \tcode{true}, and
to \tcode{PO.\exposidnc{quantity-point}.absolute_point_origin} otherwise.

\rSec2[qty.pt.static]{Static member functions}

\indexlibrarymember{min}{quantity_point}
\indexlibrarymember{max}{quantity_point}
\begin{itemdecl}
static constexpr quantity_point min() noexcept
  requires @\seebelownc@;
static constexpr quantity_point max() noexcept
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \placeholder{F} be one of \tcode{min} and \tcode{max}.

\pnum
\returns
\tcode{\{quantity_type::\placeholdernc{F}(), PO\}}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { quantity_type::@\placeholdernc{F}@(); }
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.cons]{Constructors}

\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
  requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> &&
           (point_origin == default_point_origin(R)) &&
           (implicitly_convertible(Q::quantity_spec, quantity_spec))
constexpr explicit quantity_point(FwdQ&& q);

template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
  requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ>
constexpr quantity_point(FwdQ&& q, decltype(PO));
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposidnc{quantity-from-origin} with \tcode{std::forward<FwdQ>(q)}.
\end{itemdescr}

\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{PointOrigin}@ PO2,
         @\libconcept{QuantityOf}@<PO2::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
  requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> && @\exposconceptnc{SameAbsolutePointOriginAs}@<PO2, PO>
constexpr quantity_point(FwdQ&& q, PO2);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
quantity_point(quantity_point<Q::reference, PO2{}, typename Q::rep>{std::forward<FwdQ>(q),
                                                                    PO2{}})
\end{codeblock}
\end{itemdescr}

\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
  requires std::@\stdconcept{constructible_from}@<quantity_type, typename QP::quantity_type>
constexpr explicit(!std::@\stdconcept{convertible_to}@<typename QP::quantity_type, quantity_type>)
  quantity_point(const QP& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
If \tcode{point_origin == QP::point_origin} is \tcode{true},
initializes \exposidnc{quantity-from-origin} with \tcode{qp.quantity_ref_from(point_origin)}.
Otherwise, initializes \exposidnc{quantity-from-origin} with \tcode{qp - point_origin}.
\end{itemdescr}

\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPointLike}@ QP>
  requires @\seebelownc@
constexpr explicit(@\seebelownc@) quantity_point(const QP& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Traits} be \tcode{quantity_point_like_traits<QP>}.

\pnum
\effects
Initializes \exposidnc{quantity-from-origin} with
\begin{codeblock}
Traits::to_numerical_value(qp), get_unit(Traits::reference)
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Traits::point_origin == point_origin) &&
  std::@\stdconcept{convertible_to}@<quantity<Traits::reference, typename Traits::rep>, quantity_type>
\end{codeblock}
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
Traits::explicit_import ||
  !std::@\stdconcept{convertible_to}@<quantity<Traits::reference, typename Traits::rep>, quantity_type>
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.conv]{Conversions}

\indexlibrarymember{point_for}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{SameAbsolutePointOriginAs}@<absolute_point_origin> NewPO>
constexpr @\libconcept{QuantityPointOf}@<(NewPO{})> auto point_for(NewPO new_origin) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<NewPO, decltype(point_origin)>)
  return *this;
else
  return ::mp_units::quantity_point{*this - new_origin, new_origin};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{in}{quantity_point}
\indexlibrarymember{force_in}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;

template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in() const;

template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
         @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;

template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;

template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in() const;

template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
         @\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{\placeholder{converted-quantity-expr}} be an expression denoting
the function call to the corresponding member of \tcode{quantity_ref_from(point_origin)}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity_point{@\placeholdernc{converted-quantity-expr}@, point_origin};
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\placeholdernc{converted-quantity-expr}@; }
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.obs]{Quantity value observers}

\indexlibrarymember{quantity_ref_from}{quantity_point}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO2>
  requires(PO2{} == point_origin)
constexpr quantity_type& quantity_ref_from(PO2) & noexcept;
template<@\libconcept{PointOrigin}@ PO2>
  requires(PO2{} == point_origin)
constexpr const quantity_type& quantity_ref_from(PO2) const & noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\exposidnc{quantity-from-origin}.
\end{itemdescr}

\indexlibrarymember{quantity_from}{quantity_point}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO2>
  requires requires(const quantity_point qp) { qp - PO2{}; }
constexpr @\libconcept{Quantity}@ auto quantity_from(PO2 rhs) const;

template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
constexpr @\libconcept{Quantity}@ auto quantity_from(const QP& rhs) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return *this - rhs;}
\end{itemdescr}

\indexlibrarymember{quantity_from_zero}{quantity_point}
\begin{itemdecl}
constexpr @\libconcept{Quantity}@ auto quantity_from_zero() const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { unit.@\exposidnc{point-origin}@; }) {
  // can lose the input unit
  const auto q = quantity_from(unit.@\exposidnc{point-origin}@);
  if constexpr (requires { q.in(unit); })
    // restore the unit
    return q.in(unit);
  else
    return q;
} else
  return quantity_from(absolute_point_origin);
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.conv.ops]{Conversion operations}

\indexlibrarymisc{\idxcode{quantity_point}}{\idxcode{operator QuantityPointLike}}
\begin{itemdecl}
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
  requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() const & noexcept(@\seebelownc@);
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
  requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() && noexcept(@\seebelownc@);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Traits} be \tcode{quantity_point_like_traits<QP>}.
Let \tcode{\placeholder{result-expr}} be
\begin{codeblock}
Traits::from_numerical_value(std::move(@\exposidnc{quantity-from-origin}@).@\exposidnc{numerical-value}@)
\end{codeblock}

\pnum
\returns
\tcode{\placeholdernc{result-expr}}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(point_origin == Traits::point_origin) &&
  std::@\stdconcept{convertible_to}@<quantity_type, quantity<Traits::reference, typename Traits::rep>>
\end{codeblock}
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
Traits::explicit_export ||
  !std::@\stdconcept{convertible_to}@<quantity_type, quantity<Traits::reference, typename Traits::rep>>
\end{codeblock}
Let \placeholder{T} be
\tcode{std::is_nothrow_copy_constructible_v} for the first signature, and
\tcode{std::is_nothrow_move_constructible_v} for the second signature.
The exception specification is equivalent to:
\begin{codeblock}
noexcept(@\placeholdernc{result-expr}@) && @\placeholder{T}@<rep>
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.unary.ops]{Unary operations}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator++}{quantity_point}
\indexlibrarymember{operator--}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator++(QP&& qp)
  requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator--(QP&& qp)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{@qp.\exposid{quantity-from-origin}}.

\pnum
\returns
\tcode{std::forward<QP>(qp)}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\atsign@qp.@\exposidnc{quantity-from-origin}@; }
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator++}{quantity_point}
\indexlibrarymember{operator--}{quantity_point}
\begin{itemdecl}
constexpr quantity_point operator++(int)
  requires @\seebelownc@;
constexpr quantity_point operator--(int)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return \{\exposid{quantity-from-origin}@, PO\};}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\exposid{quantity-from-origin}@@\atsign@; }
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.assign.ops]{Compound assignment operations}

\indexlibrarymember{operator+=}{quantity_point}
\indexlibrarymember{operator+=}{quantity}
\indexlibrarymember{operator-=}{quantity_point}
\indexlibrarymember{operator-=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q);
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
  requires @\seebelownc@
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.

\pnum
\effects
Equivalent to
\tcode{qp.\exposid{quantity-from-origin} @ q}.

\pnum
\returns
\tcode{std::forward<QP>(qp)}.

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2, Rep2>, quantity_type> &&
  requires { qp.@\exposid{quantity-from-origin}@ @\atsign@ q; }
\end{codeblock}
\end{itemdescr}

\rSec2[qty.pt.arith.ops]{Arithmetic operations}

\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.

\indexlibrarymember{operator+}{quantity_point}
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity_point}
\indexlibrarymember{operator-}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
  requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const quantity<R2, Rep2>& q, const QP& qp)
  requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-specialization-of}@<PO, zeroth_point_origin>())
  return ::mp_units::quantity_point{qp.quantity_ref_from(PO) @\atsign@ q};
else
  return ::mp_units::quantity_point{qp.quantity_ref_from(PO) @\atsign@ q, PO};
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{ReferenceOf}@<decltype(R2), PO.@\exposidnc{quantity-spec}@> && requires {
  qp.quantity_ref_from(PO) @\atsign@ q;
}
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{operator-}{quantity_point}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& lhs, const QP2& rhs)
  requires @\seebelownc@;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin) +
       (lhs.point_origin - rhs.point_origin);
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin); }
\end{codeblock}

\pnum
\recommended
The subtraction of two equal origins is not evaluated.
\end{itemdescr}

\indexlibrarymember{operator-}{quantity_point}
\indexlibrarymember{operator-}{PointOrigin}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
  requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& qp, PO2 po);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
  requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO2 po, const QP& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
For the first signature,
equivalent to:
\begin{codeblock}
if constexpr (point_origin == po)
  return qp.quantity_ref_from(point_origin);
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2,
                                                     ::mp_units::absolute_point_origin>()) {
  return qp.quantity_ref_from(point_origin) + (qp.point_origin - qp.absolute_point_origin);
} else {
  return qp.quantity_ref_from(point_origin) -
         po.@\exposidnc{quantity-point}@.quantity_ref_from(po.@\exposidnc{quantity-point}@.point_origin) +
         (qp.point_origin - po.@\exposidnc{quantity-point}@.point_origin);
}
\end{codeblock}
For the second signature,
equivalent to: \tcode{return -(qp - po);}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{QuantityPointOf}@<quantity_point, PO2{}> &&
  @\libconcept{ReferenceOf}@<decltype(auto(reference)), PO2::@\exposidnc{quantity-spec}@>
\end{codeblock}

\pnum
\recommended
The subtraction of two equal origins is not evaluated.
\end{itemdescr}

\rSec2[qty.pt.cmp]{Comparison}

\indexlibrarymember{operator==}{quantity_point}
\indexlibrarymember{operator<=>}{quantity_point}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
  requires @\seebelownc@
friend constexpr bool operator==(const QP& lhs, const QP2& rhs);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
  requires @\seebelownc@
friend constexpr auto operator<=>(const QP& lhs, const QP2& rhs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}, and
let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable_with}} if \tcode{@} is \tcode{<=>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
return lhs - lhs.absolute_point_origin @\atsign@ rhs - rhs.absolute_point_origin;
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\placeholder{C}@<quantity_type, typename QP2::quantity_type>
\end{codeblock}

\pnum
\recommended
If the origins are equal, instead evaluate
\begin{codeblock}
lhs.quantity_ref_from(point_origin) @\atsign@ rhs.quantity_ref_from(QP2::point_origin)
\end{codeblock}
\end{itemdescr}

\rSec2[qty.point]{Construction helper \tcode{point}}

\indexlibraryglobal{point}
\begin{codeblock}
namespace mp_units {

template<@\libconcept{Reference}@ R>
struct point_ {
  template<typename FwdRep,
           @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
  constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const;
};

}
\end{codeblock}

\indexlibrarymember{operator()}{point_}
\begin{itemdecl}
template<typename FwdRep,
         @\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity_point\{quantity\{std::forward<FwdRep>(lhs), R\{\}\}\};}
\end{itemdescr}

\rSec2[qty.pt.non.mem.conv]{Non-member conversions}

\indexlibrarymemberexpos{quantity_point}{sudo-cast}
\begin{itemdecl}
template<@\libconcept{QuantityPoint}@ ToQP, typename FwdFromQP,
         @\libconcept{QuantityPoint}@ FromQP = std::remove_cvref_t<FwdFromQP>>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{sudo-cast}@(FwdFromQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}

\pnum
\tcode{value_cast} is an explicit cast that allows truncation.

\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires(convertible(QP::reference, ToU))
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
                      QP::point_origin};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Representation}@ ToRep, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires @\libconcept{RepresentationOf}@<ToRep, QP::quantity_spec> &&
           std::@\stdconcept{constructible_from}@<ToRep, typename QP::rep>
constexpr quantity_point<QP::reference, QP::point_origin, ToRep> value_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return {value_cast<ToRep>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@), QP::point_origin};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, typename FwdQP,
         @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, typename FwdQP,
         @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToU, ToRep>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
                      QP::point_origin};
\end{codeblock}

\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(QP::reference, ToU)) && @\libconcept{RepresentationOf}@<ToRep, QP::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename QP::rep>
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Quantity}@ ToQ, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires(convertible(QP::reference, ToQ::unit)) && (ToQ::quantity_spec == QP::quantity_spec) &&
          std::@\stdconcept{constructible_from}@<typename ToQ::rep, typename QP::rep>
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
                      QP::point_origin};
\end{codeblock}
\end{itemdescr}

\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPoint}@ ToQP, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires(convertible(QP::reference, ToQP::unit)) &&
          (ToQP::quantity_spec == QP::quantity_spec) &&
          (@\exposidnc{same-absolute-point-origins}@(ToQP::point_origin, QP::point_origin)) &&
          std::@\stdconcept{constructible_from}@<typename ToQP::rep, typename QP::rep>
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return \exposidnc{sudo-cast}<ToQP>(std::forward<FwdQP>(qp));}
\end{itemdescr}

\pnum
\tcode{quantity_cast} is an explicit cast that allows converting to more specific quantities.

\indexlibrarymember{quantity_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto ToQS, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
  requires @\exposconceptnc{QuantitySpecCastableTo}@<QP::quantity_spec, ToQS>
constexpr @\libconcept{QuantityPoint}@ auto quantity_cast(FwdQP&& qp);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).@\exposidnc{quantity_from_origin}@),
          QP::point_origin};
\end{codeblock}
\end{itemdescr}

\rSec1[qty.systems]{Systems}

\rSec1[qty.chrono]{\tcode{std::chrono} interoperability}

\begin{codeblock}
namespace mp_units {

template<typename Period>
consteval auto @\exposidnc{time-unit-from-chrono-period}@()
{
  using namespace si;

  if constexpr (is_same_v<Period, std::chrono::nanoseconds::period>)
    return nano<second>;
  else if constexpr (is_same_v<Period, std::chrono::microseconds::period>)
    return micro<second>;
  else if constexpr (is_same_v<Period, std::chrono::milliseconds::period>)
    return milli<second>;
  else if constexpr (is_same_v<Period, std::chrono::seconds::period>)
    return second;
  else if constexpr (is_same_v<Period, std::chrono::minutes::period>)
    return minute;
  else if constexpr (is_same_v<Period, std::chrono::hours::period>)
    return hour;
  else if constexpr (is_same_v<Period, std::chrono::days::period>)
    return day;
  else if constexpr (is_same_v<Period, std::chrono::weeks::period>)
    return mag<7> * day;
  else
    return mag_ratio<Period::num, Period::den> * second;
}

template<typename Rep, typename Period>
struct @\libspec{quantity_like_traits}{std::chrono::duration}@<std::chrono::duration<Rep, Period>> {
  static constexpr auto reference = @\exposidnc{time-unit-from-chrono-period}@<Period>();
  static constexpr bool explicit_import = false;
  static constexpr bool explicit_export = false;
  using rep = Rep;
  using @\exposidnc{T}@ = std::chrono::duration<Rep, Period>;

  static constexpr rep to_numerical_value(const @\exposid{T}@& q) noexcept(
    std::is_nothrow_copy_constructible_v<rep>)
  {
    return q.count();
  }

  static constexpr @\exposidnc{T}@ from_numerical_value(const rep& v) noexcept(
    std::is_nothrow_copy_constructible_v<rep>)
  {
    return @\exposidnc{T}@(v);
  }
};

template<typename Clock>
struct @\libglobal{chrono_point_origin_}@ final : absolute_point_origin<isq::time> {
  using clock = Clock;
};

template<typename Clock, typename Rep, typename Period>
struct @\libspec{quantity_point_like_traits}{std::chrono::time_point}@<
  std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>> {
  static constexpr auto reference = @\exposidnc{time-unit-from-chrono-period}@<Period>();
  static constexpr auto point_origin = chrono_point_origin<Clock>;
  static constexpr bool explicit_import = false;
  static constexpr bool explicit_export = false;
  using rep = Rep;
  using @\exposidnc{T}@ = std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>;

  static constexpr rep to_numerical_value(const @\exposid{T}@& tp) noexcept(
    std::is_nothrow_copy_constructible_v<rep>)
  {
    return tp.time_since_epoch().count();
  }

  static constexpr @\exposidnc{T}@ from_numerical_value(const rep& v) noexcept(
    std::is_nothrow_copy_constructible_v<rep>)
  {
    return @\exposidnc{T}@(std::chrono::duration<Rep, Period>(v));
  }
};

}
\end{codeblock}
